shipthisapi-python 1.3.1__tar.gz → 2.1.0__tar.gz
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.
- {shipthisapi_python-1.3.1 → shipthisapi_python-2.1.0}/PKG-INFO +1 -1
- shipthisapi_python-2.1.0/ShipthisAPI/__init__.py +16 -0
- shipthisapi_python-2.1.0/ShipthisAPI/shipthisapi.py +962 -0
- {shipthisapi_python-1.3.1 → shipthisapi_python-2.1.0}/setup.py +1 -1
- {shipthisapi_python-1.3.1 → shipthisapi_python-2.1.0}/shipthisapi_python.egg-info/PKG-INFO +1 -1
- shipthisapi_python-1.3.1/ShipthisAPI/__init__.py +0 -2
- shipthisapi_python-1.3.1/ShipthisAPI/shipthisapi.py +0 -116
- {shipthisapi_python-1.3.1 → shipthisapi_python-2.1.0}/README.md +0 -0
- {shipthisapi_python-1.3.1 → shipthisapi_python-2.1.0}/setup.cfg +0 -0
- {shipthisapi_python-1.3.1 → shipthisapi_python-2.1.0}/shipthisapi_python.egg-info/SOURCES.txt +0 -0
- {shipthisapi_python-1.3.1 → shipthisapi_python-2.1.0}/shipthisapi_python.egg-info/dependency_links.txt +0 -0
- {shipthisapi_python-1.3.1 → shipthisapi_python-2.1.0}/shipthisapi_python.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# __variables__ with double-quoted values will be available in setup.py
|
|
2
|
+
__version__ = "2.1.0"
|
|
3
|
+
|
|
4
|
+
from .shipthisapi import (
|
|
5
|
+
ShipthisAPI,
|
|
6
|
+
ShipthisAPIError,
|
|
7
|
+
ShipthisAuthError,
|
|
8
|
+
ShipthisRequestError,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"ShipthisAPI",
|
|
13
|
+
"ShipthisAPIError",
|
|
14
|
+
"ShipthisAuthError",
|
|
15
|
+
"ShipthisRequestError",
|
|
16
|
+
]
|
|
@@ -0,0 +1,962 @@
|
|
|
1
|
+
"""Shipthis API Client.
|
|
2
|
+
|
|
3
|
+
A Python client for the Shipthis public API.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
from ShipthisAPI import ShipthisAPI
|
|
7
|
+
|
|
8
|
+
client = ShipthisAPI(
|
|
9
|
+
organisation="your_org_id",
|
|
10
|
+
x_api_key="your_api_key",
|
|
11
|
+
region_id="your_region",
|
|
12
|
+
location_id="your_location"
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
# Connect and validate
|
|
16
|
+
client.connect()
|
|
17
|
+
|
|
18
|
+
# Get items from a collection
|
|
19
|
+
items = client.get_list("shipment")
|
|
20
|
+
|
|
21
|
+
# Get a single item
|
|
22
|
+
item = client.get_one_item("shipment", doc_id="abc123")
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from typing import Any, Dict, List, Optional, Union
|
|
26
|
+
import json
|
|
27
|
+
import requests
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ShipthisAPIError(Exception):
|
|
31
|
+
"""Base exception for Shipthis API errors."""
|
|
32
|
+
|
|
33
|
+
def __init__(self, message: str, status_code: int = None, details: dict = None):
|
|
34
|
+
self.message = message
|
|
35
|
+
self.status_code = status_code
|
|
36
|
+
self.details = details or {}
|
|
37
|
+
super().__init__(self.message)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class ShipthisAuthError(ShipthisAPIError):
|
|
41
|
+
"""Raised when authentication fails."""
|
|
42
|
+
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class ShipthisRequestError(ShipthisAPIError):
|
|
47
|
+
"""Raised when a request fails."""
|
|
48
|
+
|
|
49
|
+
pass
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class ShipthisAPI:
|
|
53
|
+
"""Shipthis API client for public API access.
|
|
54
|
+
|
|
55
|
+
Attributes:
|
|
56
|
+
base_api_endpoint: The base URL for the API.
|
|
57
|
+
organisation_id: Your organisation ID.
|
|
58
|
+
x_api_key: Your API key.
|
|
59
|
+
user_type: User type for requests (default: "employee").
|
|
60
|
+
region_id: Region ID for requests.
|
|
61
|
+
location_id: Location ID for requests.
|
|
62
|
+
timeout: Request timeout in seconds.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
DEFAULT_TIMEOUT = 30
|
|
66
|
+
BASE_API_ENDPOINT = "https://api.shipthis.co/api/v3/"
|
|
67
|
+
|
|
68
|
+
def __init__(
|
|
69
|
+
self,
|
|
70
|
+
organisation: str,
|
|
71
|
+
x_api_key: str,
|
|
72
|
+
user_type: str = "employee",
|
|
73
|
+
region_id: str = None,
|
|
74
|
+
location_id: str = None,
|
|
75
|
+
timeout: int = None,
|
|
76
|
+
base_url: str = None,
|
|
77
|
+
) -> None:
|
|
78
|
+
"""Initialize the Shipthis API client.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
organisation: Your organisation ID.
|
|
82
|
+
x_api_key: Your API key.
|
|
83
|
+
user_type: User type for requests (default: "employee").
|
|
84
|
+
region_id: Region ID for requests.
|
|
85
|
+
location_id: Location ID for requests.
|
|
86
|
+
timeout: Request timeout in seconds (default: 30).
|
|
87
|
+
base_url: Custom base URL (optional, for testing).
|
|
88
|
+
"""
|
|
89
|
+
if not organisation:
|
|
90
|
+
raise ValueError("organisation is required")
|
|
91
|
+
if not x_api_key:
|
|
92
|
+
raise ValueError("x_api_key is required")
|
|
93
|
+
|
|
94
|
+
self.x_api_key = x_api_key
|
|
95
|
+
self.organisation_id = organisation
|
|
96
|
+
self.user_type = user_type
|
|
97
|
+
self.region_id = region_id
|
|
98
|
+
self.location_id = location_id
|
|
99
|
+
self.timeout = timeout or self.DEFAULT_TIMEOUT
|
|
100
|
+
self.base_api_endpoint = base_url or self.BASE_API_ENDPOINT
|
|
101
|
+
self.organisation_info = None
|
|
102
|
+
self.is_connected = False
|
|
103
|
+
|
|
104
|
+
def set_region_location(self, region_id: str, location_id: str) -> None:
|
|
105
|
+
"""Set the region and location for subsequent requests.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
region_id: Region ID.
|
|
109
|
+
location_id: Location ID.
|
|
110
|
+
"""
|
|
111
|
+
self.region_id = region_id
|
|
112
|
+
self.location_id = location_id
|
|
113
|
+
|
|
114
|
+
def _get_headers(self) -> Dict[str, str]:
|
|
115
|
+
"""Build request headers.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
Dictionary of headers.
|
|
119
|
+
"""
|
|
120
|
+
headers = {
|
|
121
|
+
"x-api-key": self.x_api_key,
|
|
122
|
+
"organisation": self.organisation_id,
|
|
123
|
+
"usertype": self.user_type,
|
|
124
|
+
"Content-Type": "application/json",
|
|
125
|
+
"Accept": "application/json",
|
|
126
|
+
}
|
|
127
|
+
if self.region_id:
|
|
128
|
+
headers["region"] = self.region_id
|
|
129
|
+
if self.location_id:
|
|
130
|
+
headers["location"] = self.location_id
|
|
131
|
+
return headers
|
|
132
|
+
|
|
133
|
+
def _make_request(
|
|
134
|
+
self,
|
|
135
|
+
method: str,
|
|
136
|
+
path: str,
|
|
137
|
+
query_params: Dict[str, Any] = None,
|
|
138
|
+
request_data: Dict[str, Any] = None,
|
|
139
|
+
) -> Dict[str, Any]:
|
|
140
|
+
"""Make an HTTP request to the API.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
method: HTTP method (GET, POST, PUT, PATCH, DELETE).
|
|
144
|
+
path: API endpoint path.
|
|
145
|
+
query_params: Query parameters.
|
|
146
|
+
request_data: Request body data.
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
API response data.
|
|
150
|
+
|
|
151
|
+
Raises:
|
|
152
|
+
ShipthisAuthError: If authentication fails.
|
|
153
|
+
ShipthisRequestError: If the request fails.
|
|
154
|
+
"""
|
|
155
|
+
url = self.base_api_endpoint + path
|
|
156
|
+
headers = self._get_headers()
|
|
157
|
+
|
|
158
|
+
try:
|
|
159
|
+
if request_data:
|
|
160
|
+
response = requests.request(
|
|
161
|
+
method,
|
|
162
|
+
url,
|
|
163
|
+
json=request_data,
|
|
164
|
+
headers=headers,
|
|
165
|
+
params=query_params,
|
|
166
|
+
timeout=self.timeout,
|
|
167
|
+
)
|
|
168
|
+
else:
|
|
169
|
+
response = requests.request(
|
|
170
|
+
method,
|
|
171
|
+
url,
|
|
172
|
+
headers=headers,
|
|
173
|
+
params=query_params,
|
|
174
|
+
timeout=self.timeout,
|
|
175
|
+
)
|
|
176
|
+
except requests.exceptions.Timeout:
|
|
177
|
+
raise ShipthisRequestError(
|
|
178
|
+
message="Request timed out",
|
|
179
|
+
status_code=408,
|
|
180
|
+
)
|
|
181
|
+
except requests.exceptions.ConnectionError as e:
|
|
182
|
+
raise ShipthisRequestError(
|
|
183
|
+
message=f"Connection error: {str(e)}",
|
|
184
|
+
status_code=0,
|
|
185
|
+
)
|
|
186
|
+
except requests.exceptions.RequestException as e:
|
|
187
|
+
raise ShipthisRequestError(
|
|
188
|
+
message=f"Request failed: {str(e)}",
|
|
189
|
+
status_code=0,
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
# Handle authentication errors
|
|
193
|
+
if response.status_code == 401:
|
|
194
|
+
raise ShipthisAuthError(
|
|
195
|
+
message="Authentication failed. Check your API key.",
|
|
196
|
+
status_code=401,
|
|
197
|
+
)
|
|
198
|
+
if response.status_code == 403:
|
|
199
|
+
raise ShipthisAuthError(
|
|
200
|
+
message="Access denied. Check your permissions.",
|
|
201
|
+
status_code=403,
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
# Parse response
|
|
205
|
+
try:
|
|
206
|
+
result = response.json()
|
|
207
|
+
except json.JSONDecodeError:
|
|
208
|
+
raise ShipthisRequestError(
|
|
209
|
+
message=f"Invalid JSON response: {response.text[:200]}",
|
|
210
|
+
status_code=response.status_code,
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
# Handle success
|
|
214
|
+
if response.status_code in [200, 201]:
|
|
215
|
+
if result.get("success"):
|
|
216
|
+
return result.get("data")
|
|
217
|
+
else:
|
|
218
|
+
errors = result.get("errors", [])
|
|
219
|
+
if errors and isinstance(errors, list) and len(errors) > 0:
|
|
220
|
+
error_msg = errors[0].get("message", "Unknown error")
|
|
221
|
+
else:
|
|
222
|
+
error_msg = result.get("message", "API call failed")
|
|
223
|
+
raise ShipthisRequestError(
|
|
224
|
+
message=error_msg,
|
|
225
|
+
status_code=response.status_code,
|
|
226
|
+
details=result,
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
# Handle other error status codes
|
|
230
|
+
raise ShipthisRequestError(
|
|
231
|
+
message=f"Request failed with status {response.status_code}",
|
|
232
|
+
status_code=response.status_code,
|
|
233
|
+
details=result if isinstance(result, dict) else {"response": str(result)},
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
# ==================== Connection ====================
|
|
237
|
+
|
|
238
|
+
def connect(self) -> Dict[str, Any]:
|
|
239
|
+
"""Connect and validate the API connection.
|
|
240
|
+
|
|
241
|
+
Fetches organisation info and validates region/location.
|
|
242
|
+
If no region/location is set, uses the first available one.
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
Dictionary with region_id and location_id.
|
|
246
|
+
|
|
247
|
+
Raises:
|
|
248
|
+
ShipthisAPIError: If connection fails.
|
|
249
|
+
"""
|
|
250
|
+
info = self.info()
|
|
251
|
+
self.organisation_info = info.get("organisation")
|
|
252
|
+
|
|
253
|
+
if not self.region_id or not self.location_id:
|
|
254
|
+
# Use first available region/location
|
|
255
|
+
regions = self.organisation_info.get("regions", [])
|
|
256
|
+
if regions:
|
|
257
|
+
self.region_id = regions[0].get("region_id")
|
|
258
|
+
locations = regions[0].get("locations", [])
|
|
259
|
+
if locations:
|
|
260
|
+
self.location_id = locations[0].get("location_id")
|
|
261
|
+
|
|
262
|
+
self.is_connected = True
|
|
263
|
+
return {
|
|
264
|
+
"region_id": self.region_id,
|
|
265
|
+
"location_id": self.location_id,
|
|
266
|
+
"organisation": self.organisation_info,
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
def disconnect(self) -> None:
|
|
270
|
+
"""Disconnect and clear credentials."""
|
|
271
|
+
self.x_api_key = None
|
|
272
|
+
self.is_connected = False
|
|
273
|
+
|
|
274
|
+
# ==================== Info ====================
|
|
275
|
+
|
|
276
|
+
def info(self) -> Dict[str, Any]:
|
|
277
|
+
"""Get organisation and user info.
|
|
278
|
+
|
|
279
|
+
Returns:
|
|
280
|
+
Dictionary with organisation and user information.
|
|
281
|
+
|
|
282
|
+
Raises:
|
|
283
|
+
ShipthisAPIError: If the request fails.
|
|
284
|
+
"""
|
|
285
|
+
return self._make_request("GET", "user-auth/info")
|
|
286
|
+
|
|
287
|
+
# ==================== Collection CRUD ====================
|
|
288
|
+
|
|
289
|
+
def get_one_item(
|
|
290
|
+
self,
|
|
291
|
+
collection_name: str,
|
|
292
|
+
doc_id: str = None,
|
|
293
|
+
filters: Dict[str, Any] = None,
|
|
294
|
+
only_fields: str = None,
|
|
295
|
+
) -> Optional[Dict[str, Any]]:
|
|
296
|
+
"""Get a single item from a collection.
|
|
297
|
+
|
|
298
|
+
Args:
|
|
299
|
+
collection_name: Name of the collection.
|
|
300
|
+
doc_id: Document ID (optional, if not provided returns first item).
|
|
301
|
+
filters: Query filters (optional).
|
|
302
|
+
only_fields: Comma-separated list of fields to return.
|
|
303
|
+
|
|
304
|
+
Returns:
|
|
305
|
+
Document data or None if not found.
|
|
306
|
+
|
|
307
|
+
Raises:
|
|
308
|
+
ShipthisAPIError: If the request fails.
|
|
309
|
+
"""
|
|
310
|
+
if doc_id:
|
|
311
|
+
path = f"incollection/{collection_name}/{doc_id}"
|
|
312
|
+
params = {}
|
|
313
|
+
if only_fields:
|
|
314
|
+
params["only"] = only_fields
|
|
315
|
+
return self._make_request("GET", path, query_params=params if params else None)
|
|
316
|
+
else:
|
|
317
|
+
params = {}
|
|
318
|
+
if filters:
|
|
319
|
+
params["query_filter_v2"] = json.dumps(filters)
|
|
320
|
+
if only_fields:
|
|
321
|
+
params["only"] = only_fields
|
|
322
|
+
resp = self._make_request("GET", f"incollection/{collection_name}", params)
|
|
323
|
+
if isinstance(resp, dict) and resp.get("items"):
|
|
324
|
+
return resp.get("items")[0]
|
|
325
|
+
return None
|
|
326
|
+
|
|
327
|
+
def get_list(
|
|
328
|
+
self,
|
|
329
|
+
collection_name: str,
|
|
330
|
+
filters: Dict[str, Any] = None,
|
|
331
|
+
search_query: str = None,
|
|
332
|
+
page: int = 1,
|
|
333
|
+
count: int = 20,
|
|
334
|
+
only_fields: str = None,
|
|
335
|
+
sort: List[Dict[str, Any]] = None,
|
|
336
|
+
output_type: str = None,
|
|
337
|
+
meta: bool = True,
|
|
338
|
+
) -> List[Dict[str, Any]]:
|
|
339
|
+
"""Get a list of items from a collection.
|
|
340
|
+
|
|
341
|
+
Args:
|
|
342
|
+
collection_name: Name of the collection.
|
|
343
|
+
filters: Query filters (optional).
|
|
344
|
+
search_query: Search query string (optional).
|
|
345
|
+
page: Page number (default: 1).
|
|
346
|
+
count: Items per page (default: 20).
|
|
347
|
+
only_fields: Comma-separated list of fields to return (optional).
|
|
348
|
+
sort: List of sort objects [{"field": "name", "order": "asc"}] (optional).
|
|
349
|
+
output_type: Output type (optional).
|
|
350
|
+
meta: Include metadata (default: True).
|
|
351
|
+
|
|
352
|
+
Returns:
|
|
353
|
+
List of documents.
|
|
354
|
+
|
|
355
|
+
Raises:
|
|
356
|
+
ShipthisAPIError: If the request fails.
|
|
357
|
+
"""
|
|
358
|
+
params = {"page": page, "count": count}
|
|
359
|
+
if filters:
|
|
360
|
+
params["query_filter_v2"] = json.dumps(filters)
|
|
361
|
+
if search_query:
|
|
362
|
+
params["search_query"] = search_query
|
|
363
|
+
if only_fields:
|
|
364
|
+
params["only"] = only_fields
|
|
365
|
+
if sort:
|
|
366
|
+
params["multi_sort"] = json.dumps(sort)
|
|
367
|
+
if output_type:
|
|
368
|
+
params["output_type"] = output_type
|
|
369
|
+
if not meta:
|
|
370
|
+
params["meta"] = "false"
|
|
371
|
+
|
|
372
|
+
response = self._make_request("GET", f"incollection/{collection_name}", params)
|
|
373
|
+
|
|
374
|
+
if isinstance(response, dict):
|
|
375
|
+
return response.get("items", [])
|
|
376
|
+
return []
|
|
377
|
+
|
|
378
|
+
def search(
|
|
379
|
+
self,
|
|
380
|
+
collection_name: str,
|
|
381
|
+
query: str,
|
|
382
|
+
page: int = 1,
|
|
383
|
+
count: int = 20,
|
|
384
|
+
only_fields: str = None,
|
|
385
|
+
) -> List[Dict[str, Any]]:
|
|
386
|
+
"""Search for items in a collection.
|
|
387
|
+
|
|
388
|
+
Args:
|
|
389
|
+
collection_name: Name of the collection.
|
|
390
|
+
query: Search query string.
|
|
391
|
+
page: Page number (default: 1).
|
|
392
|
+
count: Items per page (default: 20).
|
|
393
|
+
only_fields: Comma-separated list of fields to return (optional).
|
|
394
|
+
|
|
395
|
+
Returns:
|
|
396
|
+
List of matching documents.
|
|
397
|
+
|
|
398
|
+
Raises:
|
|
399
|
+
ShipthisAPIError: If the request fails.
|
|
400
|
+
"""
|
|
401
|
+
return self.get_list(
|
|
402
|
+
collection_name,
|
|
403
|
+
search_query=query,
|
|
404
|
+
page=page,
|
|
405
|
+
count=count,
|
|
406
|
+
only_fields=only_fields,
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
def create_item(
|
|
410
|
+
self, collection_name: str, data: Dict[str, Any]
|
|
411
|
+
) -> Dict[str, Any]:
|
|
412
|
+
"""Create a new item in a collection.
|
|
413
|
+
|
|
414
|
+
Args:
|
|
415
|
+
collection_name: Name of the collection.
|
|
416
|
+
data: Document data.
|
|
417
|
+
|
|
418
|
+
Returns:
|
|
419
|
+
Created document data.
|
|
420
|
+
|
|
421
|
+
Raises:
|
|
422
|
+
ShipthisAPIError: If the request fails.
|
|
423
|
+
"""
|
|
424
|
+
resp = self._make_request(
|
|
425
|
+
"POST",
|
|
426
|
+
f"incollection/{collection_name}",
|
|
427
|
+
request_data={"reqbody": data},
|
|
428
|
+
)
|
|
429
|
+
if isinstance(resp, dict) and resp.get("data"):
|
|
430
|
+
return resp.get("data")
|
|
431
|
+
return resp
|
|
432
|
+
|
|
433
|
+
def update_item(
|
|
434
|
+
self,
|
|
435
|
+
collection_name: str,
|
|
436
|
+
object_id: str,
|
|
437
|
+
updated_data: Dict[str, Any],
|
|
438
|
+
) -> Dict[str, Any]:
|
|
439
|
+
"""Update an existing item (full replacement).
|
|
440
|
+
|
|
441
|
+
Args:
|
|
442
|
+
collection_name: Name of the collection.
|
|
443
|
+
object_id: Document ID.
|
|
444
|
+
updated_data: Updated document data.
|
|
445
|
+
|
|
446
|
+
Returns:
|
|
447
|
+
Updated document data.
|
|
448
|
+
|
|
449
|
+
Raises:
|
|
450
|
+
ShipthisAPIError: If the request fails.
|
|
451
|
+
"""
|
|
452
|
+
resp = self._make_request(
|
|
453
|
+
"PUT",
|
|
454
|
+
f"incollection/{collection_name}/{object_id}",
|
|
455
|
+
request_data={"reqbody": updated_data},
|
|
456
|
+
)
|
|
457
|
+
if isinstance(resp, dict) and resp.get("data"):
|
|
458
|
+
return resp.get("data")
|
|
459
|
+
return resp
|
|
460
|
+
|
|
461
|
+
def patch_item(
|
|
462
|
+
self,
|
|
463
|
+
collection_name: str,
|
|
464
|
+
object_id: str,
|
|
465
|
+
update_fields: Dict[str, Any],
|
|
466
|
+
) -> Dict[str, Any]:
|
|
467
|
+
"""Patch specific fields of an item.
|
|
468
|
+
|
|
469
|
+
Args:
|
|
470
|
+
collection_name: Name of the collection.
|
|
471
|
+
object_id: Document ID.
|
|
472
|
+
update_fields: Fields to update.
|
|
473
|
+
|
|
474
|
+
Returns:
|
|
475
|
+
Updated document data.
|
|
476
|
+
|
|
477
|
+
Raises:
|
|
478
|
+
ShipthisAPIError: If the request fails.
|
|
479
|
+
"""
|
|
480
|
+
return self._make_request(
|
|
481
|
+
"PATCH",
|
|
482
|
+
f"incollection/{collection_name}/{object_id}",
|
|
483
|
+
request_data={"update_fields": update_fields},
|
|
484
|
+
)
|
|
485
|
+
|
|
486
|
+
def delete_item(self, collection_name: str, object_id: str) -> Dict[str, Any]:
|
|
487
|
+
"""Delete an item.
|
|
488
|
+
|
|
489
|
+
Args:
|
|
490
|
+
collection_name: Name of the collection.
|
|
491
|
+
object_id: Document ID.
|
|
492
|
+
|
|
493
|
+
Returns:
|
|
494
|
+
Deletion response.
|
|
495
|
+
|
|
496
|
+
Raises:
|
|
497
|
+
ShipthisAPIError: If the request fails.
|
|
498
|
+
"""
|
|
499
|
+
return self._make_request(
|
|
500
|
+
"DELETE",
|
|
501
|
+
f"incollection/{collection_name}/{object_id}",
|
|
502
|
+
)
|
|
503
|
+
|
|
504
|
+
# ==================== Workflow Operations ====================
|
|
505
|
+
|
|
506
|
+
def get_job_status(
|
|
507
|
+
self, collection_name: str, object_id: str
|
|
508
|
+
) -> Dict[str, Any]:
|
|
509
|
+
"""Get the job status for a document.
|
|
510
|
+
|
|
511
|
+
Args:
|
|
512
|
+
collection_name: Name of the collection.
|
|
513
|
+
object_id: Document ID.
|
|
514
|
+
|
|
515
|
+
Returns:
|
|
516
|
+
Job status data.
|
|
517
|
+
|
|
518
|
+
Raises:
|
|
519
|
+
ShipthisAPIError: If the request fails.
|
|
520
|
+
"""
|
|
521
|
+
return self._make_request(
|
|
522
|
+
"GET",
|
|
523
|
+
f"workflow/{collection_name}/job_status/{object_id}",
|
|
524
|
+
)
|
|
525
|
+
|
|
526
|
+
def set_job_status(
|
|
527
|
+
self,
|
|
528
|
+
collection_name: str,
|
|
529
|
+
object_id: str,
|
|
530
|
+
action_index: int,
|
|
531
|
+
) -> Dict[str, Any]:
|
|
532
|
+
"""Set the job status for a document.
|
|
533
|
+
|
|
534
|
+
Args:
|
|
535
|
+
collection_name: Name of the collection.
|
|
536
|
+
object_id: Document ID.
|
|
537
|
+
action_index: The index of the action to execute.
|
|
538
|
+
|
|
539
|
+
Returns:
|
|
540
|
+
Updated status data.
|
|
541
|
+
|
|
542
|
+
Raises:
|
|
543
|
+
ShipthisAPIError: If the request fails.
|
|
544
|
+
"""
|
|
545
|
+
return self._make_request(
|
|
546
|
+
"POST",
|
|
547
|
+
f"workflow/{collection_name}/job_status/{object_id}",
|
|
548
|
+
request_data={"action_index": action_index},
|
|
549
|
+
)
|
|
550
|
+
|
|
551
|
+
def get_workflow(self, object_id: str) -> Dict[str, Any]:
|
|
552
|
+
"""Get a workflow configuration.
|
|
553
|
+
|
|
554
|
+
Args:
|
|
555
|
+
object_id: Workflow ID.
|
|
556
|
+
|
|
557
|
+
Returns:
|
|
558
|
+
Workflow data.
|
|
559
|
+
|
|
560
|
+
Raises:
|
|
561
|
+
ShipthisAPIError: If the request fails.
|
|
562
|
+
"""
|
|
563
|
+
return self._make_request("GET", f"incollection/workflow/{object_id}")
|
|
564
|
+
|
|
565
|
+
# ==================== Reports ====================
|
|
566
|
+
|
|
567
|
+
def get_report_view(
|
|
568
|
+
self,
|
|
569
|
+
report_name: str,
|
|
570
|
+
start_date: str,
|
|
571
|
+
end_date: str,
|
|
572
|
+
post_data: Dict[str, Any] = None,
|
|
573
|
+
output_type: str = "json",
|
|
574
|
+
skip_meta: bool = True,
|
|
575
|
+
) -> Dict[str, Any]:
|
|
576
|
+
"""Get a report view.
|
|
577
|
+
|
|
578
|
+
Args:
|
|
579
|
+
report_name: Name of the report.
|
|
580
|
+
start_date: Start date (YYYY-MM-DD or timestamp).
|
|
581
|
+
end_date: End date (YYYY-MM-DD or timestamp).
|
|
582
|
+
post_data: Additional filter data (optional).
|
|
583
|
+
output_type: Output format (default: "json").
|
|
584
|
+
skip_meta: Skip metadata (default: True).
|
|
585
|
+
|
|
586
|
+
Returns:
|
|
587
|
+
Report data.
|
|
588
|
+
|
|
589
|
+
Raises:
|
|
590
|
+
ShipthisAPIError: If the request fails.
|
|
591
|
+
"""
|
|
592
|
+
params = {
|
|
593
|
+
"start_date": start_date,
|
|
594
|
+
"end_date": end_date,
|
|
595
|
+
"output_type": output_type,
|
|
596
|
+
"skip_meta": "true" if skip_meta else "false",
|
|
597
|
+
}
|
|
598
|
+
if self.location_id:
|
|
599
|
+
params["location"] = self.location_id
|
|
600
|
+
|
|
601
|
+
return self._make_request(
|
|
602
|
+
"POST",
|
|
603
|
+
f"report-view/{report_name}",
|
|
604
|
+
query_params=params,
|
|
605
|
+
request_data=post_data,
|
|
606
|
+
)
|
|
607
|
+
|
|
608
|
+
# ==================== Third-party Services ====================
|
|
609
|
+
|
|
610
|
+
def get_exchange_rate(
|
|
611
|
+
self,
|
|
612
|
+
source_currency: str,
|
|
613
|
+
target_currency: str = "USD",
|
|
614
|
+
date: int = None,
|
|
615
|
+
) -> Dict[str, Any]:
|
|
616
|
+
"""Get exchange rate between currencies.
|
|
617
|
+
|
|
618
|
+
Args:
|
|
619
|
+
source_currency: Source currency code (e.g., "EUR").
|
|
620
|
+
target_currency: Target currency code (default: "USD").
|
|
621
|
+
date: Date timestamp in milliseconds (optional, defaults to now).
|
|
622
|
+
|
|
623
|
+
Returns:
|
|
624
|
+
Exchange rate data.
|
|
625
|
+
|
|
626
|
+
Raises:
|
|
627
|
+
ShipthisAPIError: If the request fails.
|
|
628
|
+
"""
|
|
629
|
+
import time
|
|
630
|
+
if date is None:
|
|
631
|
+
date = int(time.time() * 1000)
|
|
632
|
+
|
|
633
|
+
return self._make_request(
|
|
634
|
+
"GET",
|
|
635
|
+
f"thirdparty/currency?source={source_currency}&target={target_currency}&date={date}",
|
|
636
|
+
)
|
|
637
|
+
|
|
638
|
+
def autocomplete(
|
|
639
|
+
self,
|
|
640
|
+
reference_name: str,
|
|
641
|
+
data: Dict[str, Any],
|
|
642
|
+
) -> List[Dict[str, Any]]:
|
|
643
|
+
"""Get autocomplete suggestions for a reference field.
|
|
644
|
+
|
|
645
|
+
Args:
|
|
646
|
+
reference_name: Name of the reference (e.g., "port", "airport").
|
|
647
|
+
data: Search data with query.
|
|
648
|
+
|
|
649
|
+
Returns:
|
|
650
|
+
List of suggestions.
|
|
651
|
+
|
|
652
|
+
Raises:
|
|
653
|
+
ShipthisAPIError: If the request fails.
|
|
654
|
+
"""
|
|
655
|
+
params = {}
|
|
656
|
+
if self.location_id:
|
|
657
|
+
params["location"] = self.location_id
|
|
658
|
+
|
|
659
|
+
return self._make_request(
|
|
660
|
+
"POST",
|
|
661
|
+
f"autocomplete-reference/{reference_name}",
|
|
662
|
+
query_params=params if params else None,
|
|
663
|
+
request_data=data,
|
|
664
|
+
)
|
|
665
|
+
|
|
666
|
+
def search_location(self, query: str) -> List[Dict[str, Any]]:
|
|
667
|
+
"""Search for locations using Google Places.
|
|
668
|
+
|
|
669
|
+
Args:
|
|
670
|
+
query: Search query string.
|
|
671
|
+
|
|
672
|
+
Returns:
|
|
673
|
+
List of location suggestions.
|
|
674
|
+
|
|
675
|
+
Raises:
|
|
676
|
+
ShipthisAPIError: If the request fails.
|
|
677
|
+
"""
|
|
678
|
+
return self._make_request(
|
|
679
|
+
"GET",
|
|
680
|
+
f"thirdparty/search-place-autocomplete?query={query}",
|
|
681
|
+
)
|
|
682
|
+
|
|
683
|
+
def get_place_details(
|
|
684
|
+
self,
|
|
685
|
+
place_id: str,
|
|
686
|
+
description: str = "",
|
|
687
|
+
) -> Dict[str, Any]:
|
|
688
|
+
"""Get details for a Google Place.
|
|
689
|
+
|
|
690
|
+
Args:
|
|
691
|
+
place_id: Google Place ID.
|
|
692
|
+
description: Place description (optional).
|
|
693
|
+
|
|
694
|
+
Returns:
|
|
695
|
+
Place details.
|
|
696
|
+
|
|
697
|
+
Raises:
|
|
698
|
+
ShipthisAPIError: If the request fails.
|
|
699
|
+
"""
|
|
700
|
+
return self._make_request(
|
|
701
|
+
"GET",
|
|
702
|
+
f"thirdparty/select-google-place?query={place_id}&description={description}",
|
|
703
|
+
)
|
|
704
|
+
|
|
705
|
+
# ==================== Conversations ====================
|
|
706
|
+
|
|
707
|
+
def create_conversation(
|
|
708
|
+
self,
|
|
709
|
+
view_name: str,
|
|
710
|
+
document_id: str,
|
|
711
|
+
conversation_data: Dict[str, Any],
|
|
712
|
+
) -> Dict[str, Any]:
|
|
713
|
+
"""Create a conversation/message on a document.
|
|
714
|
+
|
|
715
|
+
Args:
|
|
716
|
+
view_name: Collection/view name.
|
|
717
|
+
document_id: Document ID.
|
|
718
|
+
conversation_data: Conversation data (message, type, etc.).
|
|
719
|
+
|
|
720
|
+
Returns:
|
|
721
|
+
Created conversation data.
|
|
722
|
+
|
|
723
|
+
Raises:
|
|
724
|
+
ShipthisAPIError: If the request fails.
|
|
725
|
+
"""
|
|
726
|
+
payload = {
|
|
727
|
+
"conversation": conversation_data,
|
|
728
|
+
"document_id": document_id,
|
|
729
|
+
"view_name": view_name,
|
|
730
|
+
"message_type": conversation_data.get("type", ""),
|
|
731
|
+
}
|
|
732
|
+
return self._make_request("POST", "conversation", request_data=payload)
|
|
733
|
+
|
|
734
|
+
def get_conversations(
|
|
735
|
+
self,
|
|
736
|
+
view_name: str,
|
|
737
|
+
document_id: str,
|
|
738
|
+
message_type: str = "all",
|
|
739
|
+
page: int = 1,
|
|
740
|
+
count: int = 100,
|
|
741
|
+
) -> Dict[str, Any]:
|
|
742
|
+
"""Get conversations for a document.
|
|
743
|
+
|
|
744
|
+
Args:
|
|
745
|
+
view_name: Collection/view name.
|
|
746
|
+
document_id: Document ID.
|
|
747
|
+
message_type: Filter by message type (default: "all").
|
|
748
|
+
page: Page number (default: 1).
|
|
749
|
+
count: Items per page (default: 100).
|
|
750
|
+
|
|
751
|
+
Returns:
|
|
752
|
+
Conversations data.
|
|
753
|
+
|
|
754
|
+
Raises:
|
|
755
|
+
ShipthisAPIError: If the request fails.
|
|
756
|
+
"""
|
|
757
|
+
params = {
|
|
758
|
+
"view_name": view_name,
|
|
759
|
+
"document_id": document_id,
|
|
760
|
+
"page": str(page),
|
|
761
|
+
"count": str(count),
|
|
762
|
+
"message_type": message_type,
|
|
763
|
+
"version": "2",
|
|
764
|
+
}
|
|
765
|
+
return self._make_request("GET", "conversation", query_params=params)
|
|
766
|
+
|
|
767
|
+
# ==================== Bulk Operations ====================
|
|
768
|
+
|
|
769
|
+
def bulk_edit(
|
|
770
|
+
self,
|
|
771
|
+
collection_name: str,
|
|
772
|
+
ids: List[str],
|
|
773
|
+
update_data: Dict[str, Any],
|
|
774
|
+
external_update_data: Dict[str, Any] = None,
|
|
775
|
+
) -> Dict[str, Any]:
|
|
776
|
+
"""Bulk edit multiple items in a collection.
|
|
777
|
+
|
|
778
|
+
Args:
|
|
779
|
+
collection_name: Name of the collection.
|
|
780
|
+
ids: List of document IDs to update.
|
|
781
|
+
update_data: Key-value pairs of fields to update.
|
|
782
|
+
external_update_data: Extra data for external updates (optional).
|
|
783
|
+
|
|
784
|
+
Returns:
|
|
785
|
+
Update response.
|
|
786
|
+
|
|
787
|
+
Raises:
|
|
788
|
+
ShipthisAPIError: If the request fails.
|
|
789
|
+
|
|
790
|
+
Example:
|
|
791
|
+
client.bulk_edit(
|
|
792
|
+
"customer",
|
|
793
|
+
ids=["5fdc00487f7636c97b9fa064", "608fe19fc33215427867f34e"],
|
|
794
|
+
update_data={"company.fax_no": "12323231", "address.state": "California"}
|
|
795
|
+
)
|
|
796
|
+
"""
|
|
797
|
+
payload = {
|
|
798
|
+
"data": {
|
|
799
|
+
"ids": ids,
|
|
800
|
+
"update_data": update_data,
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
if external_update_data:
|
|
804
|
+
payload["data"]["external_update_data"] = external_update_data
|
|
805
|
+
|
|
806
|
+
return self._make_request(
|
|
807
|
+
"POST",
|
|
808
|
+
f"incollection_group_edit/{collection_name}",
|
|
809
|
+
request_data=payload,
|
|
810
|
+
)
|
|
811
|
+
|
|
812
|
+
# ==================== Workflow Actions ====================
|
|
813
|
+
|
|
814
|
+
def primary_workflow_action(
|
|
815
|
+
self,
|
|
816
|
+
collection: str,
|
|
817
|
+
workflow_id: str,
|
|
818
|
+
object_id: str,
|
|
819
|
+
action_index: int,
|
|
820
|
+
intended_state_id: str,
|
|
821
|
+
start_state_id: str = None,
|
|
822
|
+
) -> Dict[str, Any]:
|
|
823
|
+
"""Trigger a primary workflow transition (status change on a record).
|
|
824
|
+
|
|
825
|
+
Args:
|
|
826
|
+
collection: Target collection (e.g., "pickup_delivery", "sea_shipment").
|
|
827
|
+
workflow_id: Workflow status key (e.g., "job_status").
|
|
828
|
+
object_id: The document's ID.
|
|
829
|
+
action_index: Index of action within the status.
|
|
830
|
+
intended_state_id: Intended resulting state ID (e.g., "ops_complete").
|
|
831
|
+
start_state_id: Current/starting state ID (optional).
|
|
832
|
+
|
|
833
|
+
Returns:
|
|
834
|
+
Workflow action response with success status and resulting state.
|
|
835
|
+
|
|
836
|
+
Raises:
|
|
837
|
+
ShipthisAPIError: If the request fails.
|
|
838
|
+
|
|
839
|
+
Example:
|
|
840
|
+
client.primary_workflow_action(
|
|
841
|
+
collection="pickup_delivery",
|
|
842
|
+
workflow_id="job_status",
|
|
843
|
+
object_id="68a4f906743189ad061429a7",
|
|
844
|
+
action_index=0,
|
|
845
|
+
intended_state_id="ops_complete",
|
|
846
|
+
start_state_id="closed"
|
|
847
|
+
)
|
|
848
|
+
"""
|
|
849
|
+
payload = {
|
|
850
|
+
"action_index": action_index,
|
|
851
|
+
"intended_state_id": intended_state_id,
|
|
852
|
+
}
|
|
853
|
+
if start_state_id:
|
|
854
|
+
payload["start_state_id"] = start_state_id
|
|
855
|
+
|
|
856
|
+
return self._make_request(
|
|
857
|
+
"POST",
|
|
858
|
+
f"workflow/{collection}/{workflow_id}/{object_id}",
|
|
859
|
+
request_data=payload,
|
|
860
|
+
)
|
|
861
|
+
|
|
862
|
+
def secondary_workflow_action(
|
|
863
|
+
self,
|
|
864
|
+
collection: str,
|
|
865
|
+
workflow_id: str,
|
|
866
|
+
object_id: str,
|
|
867
|
+
target_state: str,
|
|
868
|
+
additional_data: Dict[str, Any] = None,
|
|
869
|
+
) -> Dict[str, Any]:
|
|
870
|
+
"""Trigger a secondary workflow transition (sub-status change).
|
|
871
|
+
|
|
872
|
+
Args:
|
|
873
|
+
collection: Target collection (e.g., "pickup_delivery").
|
|
874
|
+
workflow_id: Secondary status key (e.g., "driver_status").
|
|
875
|
+
object_id: The document's ID.
|
|
876
|
+
target_state: Resulting sub-state (e.g., "to_pick_up").
|
|
877
|
+
additional_data: Optional additional data to send with the request.
|
|
878
|
+
|
|
879
|
+
Returns:
|
|
880
|
+
Workflow action response.
|
|
881
|
+
|
|
882
|
+
Raises:
|
|
883
|
+
ShipthisAPIError: If the request fails.
|
|
884
|
+
|
|
885
|
+
Example:
|
|
886
|
+
client.secondary_workflow_action(
|
|
887
|
+
collection="pickup_delivery",
|
|
888
|
+
workflow_id="driver_status",
|
|
889
|
+
object_id="67ed10859b7cf551a19f813e",
|
|
890
|
+
target_state="to_pick_up"
|
|
891
|
+
)
|
|
892
|
+
"""
|
|
893
|
+
payload = additional_data or {}
|
|
894
|
+
|
|
895
|
+
return self._make_request(
|
|
896
|
+
"POST",
|
|
897
|
+
f"workflow/{collection}/{workflow_id}/{object_id}/{target_state}",
|
|
898
|
+
request_data=payload,
|
|
899
|
+
)
|
|
900
|
+
|
|
901
|
+
# ==================== File Upload ====================
|
|
902
|
+
|
|
903
|
+
def upload_file(
|
|
904
|
+
self,
|
|
905
|
+
file_path: str,
|
|
906
|
+
file_name: str = None,
|
|
907
|
+
) -> Dict[str, Any]:
|
|
908
|
+
"""Upload a file.
|
|
909
|
+
|
|
910
|
+
Args:
|
|
911
|
+
file_path: Path to the file to upload.
|
|
912
|
+
file_name: Custom file name (optional).
|
|
913
|
+
|
|
914
|
+
Returns:
|
|
915
|
+
Upload response with file URL.
|
|
916
|
+
|
|
917
|
+
Raises:
|
|
918
|
+
ShipthisAPIError: If the request fails.
|
|
919
|
+
"""
|
|
920
|
+
import os
|
|
921
|
+
|
|
922
|
+
if file_name is None:
|
|
923
|
+
file_name = os.path.basename(file_path)
|
|
924
|
+
|
|
925
|
+
upload_url = self.base_api_endpoint.replace("/api/v3/", "").rstrip("/")
|
|
926
|
+
upload_url = upload_url.replace("api.", "upload.")
|
|
927
|
+
upload_url = f"{upload_url}/api/v3/file-upload"
|
|
928
|
+
|
|
929
|
+
headers = self._get_headers()
|
|
930
|
+
# Remove Content-Type for multipart
|
|
931
|
+
headers.pop("Content-Type", None)
|
|
932
|
+
|
|
933
|
+
try:
|
|
934
|
+
with open(file_path, "rb") as f:
|
|
935
|
+
files = {"file": (file_name, f)}
|
|
936
|
+
response = requests.post(
|
|
937
|
+
upload_url,
|
|
938
|
+
headers=headers,
|
|
939
|
+
files=files,
|
|
940
|
+
timeout=self.timeout * 2, # Double timeout for uploads
|
|
941
|
+
)
|
|
942
|
+
except FileNotFoundError:
|
|
943
|
+
raise ShipthisRequestError(
|
|
944
|
+
message=f"File not found: {file_path}",
|
|
945
|
+
status_code=0,
|
|
946
|
+
)
|
|
947
|
+
except requests.exceptions.RequestException as e:
|
|
948
|
+
raise ShipthisRequestError(
|
|
949
|
+
message=f"Upload failed: {str(e)}",
|
|
950
|
+
status_code=0,
|
|
951
|
+
)
|
|
952
|
+
|
|
953
|
+
if response.status_code == 200:
|
|
954
|
+
try:
|
|
955
|
+
return response.json()
|
|
956
|
+
except json.JSONDecodeError:
|
|
957
|
+
return {"url": response.text}
|
|
958
|
+
|
|
959
|
+
raise ShipthisRequestError(
|
|
960
|
+
message=f"Upload failed with status {response.status_code}",
|
|
961
|
+
status_code=response.status_code,
|
|
962
|
+
)
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
from typing import Dict, List
|
|
2
|
-
import requests
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class ShipthisAPI:
|
|
6
|
-
base_api_endpoint = "https://api.shipthis.co/api/v3/"
|
|
7
|
-
|
|
8
|
-
def __init__(
|
|
9
|
-
self,
|
|
10
|
-
organisation: str,
|
|
11
|
-
x_api_key: str,
|
|
12
|
-
user_type="employee",
|
|
13
|
-
region_id: str = None,
|
|
14
|
-
location_id: str = None,
|
|
15
|
-
) -> None:
|
|
16
|
-
self.x_api_key = x_api_key
|
|
17
|
-
self.organisation_id = organisation
|
|
18
|
-
self.user_type = user_type
|
|
19
|
-
self.region_id = region_id
|
|
20
|
-
self.location_id = location_id
|
|
21
|
-
|
|
22
|
-
def set_region_location(self, region_id, location_id):
|
|
23
|
-
self.region_id = region_id
|
|
24
|
-
self.location_id = location_id
|
|
25
|
-
|
|
26
|
-
def _make_request(
|
|
27
|
-
self, method: str, path: str, query_params: str = None, request_data=None
|
|
28
|
-
) -> None:
|
|
29
|
-
headers = {
|
|
30
|
-
"x-api-key": self.x_api_key,
|
|
31
|
-
"organisation": self.organisation_id,
|
|
32
|
-
"user_type": self.user_type,
|
|
33
|
-
"location": "new_york",
|
|
34
|
-
}
|
|
35
|
-
fetched_response = requests.request(
|
|
36
|
-
method,
|
|
37
|
-
self.base_api_endpoint + path,
|
|
38
|
-
data=request_data or {},
|
|
39
|
-
headers=headers,
|
|
40
|
-
params=query_params,
|
|
41
|
-
)
|
|
42
|
-
result = fetched_response.json()
|
|
43
|
-
|
|
44
|
-
if fetched_response.status_code == 200:
|
|
45
|
-
if result.get("success"):
|
|
46
|
-
return result.get("data")
|
|
47
|
-
else:
|
|
48
|
-
error_message = (
|
|
49
|
-
result.get("errors")
|
|
50
|
-
or "API call failed. Please check your internet connection or try again later"
|
|
51
|
-
)
|
|
52
|
-
return (
|
|
53
|
-
error_message[0].get("message")
|
|
54
|
-
if error_message[0].get("message")
|
|
55
|
-
else "Please provide the necessary requirements or try again later"
|
|
56
|
-
)
|
|
57
|
-
else:
|
|
58
|
-
return f"Request failed with status {fetched_response.status_code}: {fetched_response.text}"
|
|
59
|
-
|
|
60
|
-
def info(self) -> Dict:
|
|
61
|
-
info_resp = self._make_request("GET", "auth/info")
|
|
62
|
-
return info_resp
|
|
63
|
-
|
|
64
|
-
def get_one_item(self, collection_name: str, params=None) -> Dict:
|
|
65
|
-
resp = self._make_request("GET", "incollection/" + collection_name)
|
|
66
|
-
if isinstance(resp, dict):
|
|
67
|
-
if resp.get("items"):
|
|
68
|
-
# return first elem
|
|
69
|
-
return resp.get("items")[0]
|
|
70
|
-
else:
|
|
71
|
-
return resp
|
|
72
|
-
|
|
73
|
-
def get_list(self, collection_name: str, params=None) -> List[Dict] or str:
|
|
74
|
-
get_list_response = self._make_request(
|
|
75
|
-
"GET", "incollection/" + collection_name, params
|
|
76
|
-
)
|
|
77
|
-
if isinstance(get_list_response, str):
|
|
78
|
-
return get_list_response
|
|
79
|
-
else:
|
|
80
|
-
if get_list_response.get("items", False):
|
|
81
|
-
return get_list_response.get("items", [])
|
|
82
|
-
else:
|
|
83
|
-
return get_list_response
|
|
84
|
-
|
|
85
|
-
def create_item(self, collection_name: str, data=None) -> Dict:
|
|
86
|
-
resp = self._make_request(
|
|
87
|
-
"POST", "incollection/" + collection_name, request_data={"reqbody": data}
|
|
88
|
-
)
|
|
89
|
-
if isinstance(resp, dict):
|
|
90
|
-
if resp.get("data"):
|
|
91
|
-
return resp.get("data")
|
|
92
|
-
else:
|
|
93
|
-
return resp
|
|
94
|
-
|
|
95
|
-
def update_item(
|
|
96
|
-
self, collection_name: str, object_id: str, updated_data=None
|
|
97
|
-
) -> Dict:
|
|
98
|
-
resp = self._make_request(
|
|
99
|
-
"PUT",
|
|
100
|
-
"incollection/" + collection_name + "/" + object_id,
|
|
101
|
-
request_data={"reqbody": updated_data},
|
|
102
|
-
)
|
|
103
|
-
if isinstance(resp, dict):
|
|
104
|
-
if resp.get("data"):
|
|
105
|
-
return resp.get("data")
|
|
106
|
-
else:
|
|
107
|
-
return resp
|
|
108
|
-
|
|
109
|
-
def delete_item(self, collection_name: str, object_id: str) -> Dict:
|
|
110
|
-
resp = self._make_request(
|
|
111
|
-
"DELETE", "incollection/" + collection_name + "/" + object_id
|
|
112
|
-
)
|
|
113
|
-
# if isinstance(resp, str):
|
|
114
|
-
# return resp
|
|
115
|
-
# else:
|
|
116
|
-
return resp
|
|
File without changes
|
|
File without changes
|
{shipthisapi_python-1.3.1 → shipthisapi_python-2.1.0}/shipthisapi_python.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{shipthisapi_python-1.3.1 → shipthisapi_python-2.1.0}/shipthisapi_python.egg-info/top_level.txt
RENAMED
|
File without changes
|