vesremont-api 0.2.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.
- vesremont_api-0.2.0/LICENSE +21 -0
- vesremont_api-0.2.0/PKG-INFO +70 -0
- vesremont_api-0.2.0/README.md +53 -0
- vesremont_api-0.2.0/pyproject.toml +23 -0
- vesremont_api-0.2.0/setup.cfg +4 -0
- vesremont_api-0.2.0/vesremont_api.egg-info/PKG-INFO +70 -0
- vesremont_api-0.2.0/vesremont_api.egg-info/SOURCES.txt +8 -0
- vesremont_api-0.2.0/vesremont_api.egg-info/dependency_links.txt +1 -0
- vesremont_api-0.2.0/vesremont_api.egg-info/top_level.txt +1 -0
- vesremont_api-0.2.0/vesremont_api.py +108 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Vesremont
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vesremont-api
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Small standard-library client for the Vesremont public API
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Documentation, https://vesremont.com/for_ai/api_ai/
|
|
7
|
+
Project-URL: Homepage, https://vesremont.com/developers/
|
|
8
|
+
Project-URL: Source, https://github.com/oooafganec-dev/vesremont-sdk/tree/main/python
|
|
9
|
+
Project-URL: Issues, https://github.com/oooafganec-dev/vesremont-sdk/issues
|
|
10
|
+
Keywords: vesremont,api,sdk,oauth,pkce
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Requires-Python: >=3.10
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Dynamic: license-file
|
|
17
|
+
|
|
18
|
+
# Vesremont Python SDK 0.2.0
|
|
19
|
+
|
|
20
|
+
Python 3.10+, только стандартная библиотека во время работы.
|
|
21
|
+
MIT. Официальные исходники:
|
|
22
|
+
https://github.com/oooafganec-dev/vesremont-sdk/tree/main/python.
|
|
23
|
+
Команда установки опубликованного релиза из PyPI:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
python -m pip install vesremont-api==0.2.0
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Альтернатива — прямой wheel с сайта Vesremont:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
python -m pip install https://vesremont.com/developers/downloads/vesremont_api-0.2.0-py3-none-any.whl
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Готовый wheel не требует сборки. Также доступен исходный sdist
|
|
36
|
+
`vesremont_api-0.2.0.tar.gz`; для его сборки нужен setuptools 77.0.3+.
|
|
37
|
+
Runtime-зависимостей нет.
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from vesremont_api import VesremontClient, ApiError
|
|
41
|
+
|
|
42
|
+
api = VesremontClient()
|
|
43
|
+
products = api.search("труборез", page=1, per_page=10)
|
|
44
|
+
product = api.product(375094)
|
|
45
|
+
draft = api.cart_draft(375094, 1)
|
|
46
|
+
# draft["share_url"] передаётся покупателю, не в публичные логи.
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`status`, `search`, `product`, `cart`, `cart_draft` — короткие помощники.
|
|
50
|
+
Остальные REST-операции: `request(method, '/path', query={}, body={}, idempotency_key=...)`.
|
|
51
|
+
Путь относительно `/api/v1`; GET вызывается без body. `filters` в query — JSON-строка.
|
|
52
|
+
Подборку можно дополнить через `cart_draft(..., draft=token)`; token берётся
|
|
53
|
+
из query `draft` ранее полученной share_url. Серверные схемы:
|
|
54
|
+
https://vesremont.com/openapi.json.
|
|
55
|
+
|
|
56
|
+
Для личных данных передайте уже полученный REST OAuth token:
|
|
57
|
+
`VesremontClient(token=token)`. OAuth-протокол и минимальные scopes описаны
|
|
58
|
+
в https://vesremont.com/llms/api.md. Браузерный OAuth мастер есть в Node CLI;
|
|
59
|
+
в Python SDK второй мастер не дублируется. Токен не пишется на диск, не входит в URL.
|
|
60
|
+
|
|
61
|
+
Timeout по умолчанию 15 секунд (параметр `timeout`, до 60). TLS проверяется,
|
|
62
|
+
redirects и автоматические повторы отсутствуют; API host фиксирован.
|
|
63
|
+
Ответ ограничен 2 MiB, тело запроса — 64 KiB.
|
|
64
|
+
`ApiError` содержит `status`, `code`, `request_id`, `retry_after`, без raw body.
|
|
65
|
+
После неопределённого исхода записи сначала перечитайте состояние.
|
|
66
|
+
Для submit нужны prepare, подтверждение покупателя на Vesremont и стабильный
|
|
67
|
+
`idempotency_key`; SDK не обходит эти проверки и не создаёт фиктивных заказов.
|
|
68
|
+
|
|
69
|
+
Используйте с внешнего ПК/хостинга. Это production API, sandbox не предоставляется.
|
|
70
|
+
Наличие SDK не означает включение отключённых операций или завершение приёмки.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Vesremont Python SDK 0.2.0
|
|
2
|
+
|
|
3
|
+
Python 3.10+, только стандартная библиотека во время работы.
|
|
4
|
+
MIT. Официальные исходники:
|
|
5
|
+
https://github.com/oooafganec-dev/vesremont-sdk/tree/main/python.
|
|
6
|
+
Команда установки опубликованного релиза из PyPI:
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
python -m pip install vesremont-api==0.2.0
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Альтернатива — прямой wheel с сайта Vesremont:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
python -m pip install https://vesremont.com/developers/downloads/vesremont_api-0.2.0-py3-none-any.whl
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Готовый wheel не требует сборки. Также доступен исходный sdist
|
|
19
|
+
`vesremont_api-0.2.0.tar.gz`; для его сборки нужен setuptools 77.0.3+.
|
|
20
|
+
Runtime-зависимостей нет.
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from vesremont_api import VesremontClient, ApiError
|
|
24
|
+
|
|
25
|
+
api = VesremontClient()
|
|
26
|
+
products = api.search("труборез", page=1, per_page=10)
|
|
27
|
+
product = api.product(375094)
|
|
28
|
+
draft = api.cart_draft(375094, 1)
|
|
29
|
+
# draft["share_url"] передаётся покупателю, не в публичные логи.
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
`status`, `search`, `product`, `cart`, `cart_draft` — короткие помощники.
|
|
33
|
+
Остальные REST-операции: `request(method, '/path', query={}, body={}, idempotency_key=...)`.
|
|
34
|
+
Путь относительно `/api/v1`; GET вызывается без body. `filters` в query — JSON-строка.
|
|
35
|
+
Подборку можно дополнить через `cart_draft(..., draft=token)`; token берётся
|
|
36
|
+
из query `draft` ранее полученной share_url. Серверные схемы:
|
|
37
|
+
https://vesremont.com/openapi.json.
|
|
38
|
+
|
|
39
|
+
Для личных данных передайте уже полученный REST OAuth token:
|
|
40
|
+
`VesremontClient(token=token)`. OAuth-протокол и минимальные scopes описаны
|
|
41
|
+
в https://vesremont.com/llms/api.md. Браузерный OAuth мастер есть в Node CLI;
|
|
42
|
+
в Python SDK второй мастер не дублируется. Токен не пишется на диск, не входит в URL.
|
|
43
|
+
|
|
44
|
+
Timeout по умолчанию 15 секунд (параметр `timeout`, до 60). TLS проверяется,
|
|
45
|
+
redirects и автоматические повторы отсутствуют; API host фиксирован.
|
|
46
|
+
Ответ ограничен 2 MiB, тело запроса — 64 KiB.
|
|
47
|
+
`ApiError` содержит `status`, `code`, `request_id`, `retry_after`, без raw body.
|
|
48
|
+
После неопределённого исхода записи сначала перечитайте состояние.
|
|
49
|
+
Для submit нужны prepare, подтверждение покупателя на Vesremont и стабильный
|
|
50
|
+
`idempotency_key`; SDK не обходит эти проверки и не создаёт фиктивных заказов.
|
|
51
|
+
|
|
52
|
+
Используйте с внешнего ПК/хостинга. Это production API, sandbox не предоставляется.
|
|
53
|
+
Наличие SDK не означает включение отключённых операций или завершение приёмки.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77.0.3"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "vesremont-api"
|
|
7
|
+
version = "0.2.0"
|
|
8
|
+
description = "Small standard-library client for the Vesremont public API"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
keywords = ["vesremont", "api", "sdk", "oauth", "pkce"]
|
|
14
|
+
classifiers = ["Programming Language :: Python :: 3", "Operating System :: OS Independent"]
|
|
15
|
+
|
|
16
|
+
[project.urls]
|
|
17
|
+
Documentation = "https://vesremont.com/for_ai/api_ai/"
|
|
18
|
+
Homepage = "https://vesremont.com/developers/"
|
|
19
|
+
Source = "https://github.com/oooafganec-dev/vesremont-sdk/tree/main/python"
|
|
20
|
+
Issues = "https://github.com/oooafganec-dev/vesremont-sdk/issues"
|
|
21
|
+
|
|
22
|
+
[tool.setuptools]
|
|
23
|
+
py-modules = ["vesremont_api"]
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vesremont-api
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Small standard-library client for the Vesremont public API
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Documentation, https://vesremont.com/for_ai/api_ai/
|
|
7
|
+
Project-URL: Homepage, https://vesremont.com/developers/
|
|
8
|
+
Project-URL: Source, https://github.com/oooafganec-dev/vesremont-sdk/tree/main/python
|
|
9
|
+
Project-URL: Issues, https://github.com/oooafganec-dev/vesremont-sdk/issues
|
|
10
|
+
Keywords: vesremont,api,sdk,oauth,pkce
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Requires-Python: >=3.10
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Dynamic: license-file
|
|
17
|
+
|
|
18
|
+
# Vesremont Python SDK 0.2.0
|
|
19
|
+
|
|
20
|
+
Python 3.10+, только стандартная библиотека во время работы.
|
|
21
|
+
MIT. Официальные исходники:
|
|
22
|
+
https://github.com/oooafganec-dev/vesremont-sdk/tree/main/python.
|
|
23
|
+
Команда установки опубликованного релиза из PyPI:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
python -m pip install vesremont-api==0.2.0
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Альтернатива — прямой wheel с сайта Vesremont:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
python -m pip install https://vesremont.com/developers/downloads/vesremont_api-0.2.0-py3-none-any.whl
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Готовый wheel не требует сборки. Также доступен исходный sdist
|
|
36
|
+
`vesremont_api-0.2.0.tar.gz`; для его сборки нужен setuptools 77.0.3+.
|
|
37
|
+
Runtime-зависимостей нет.
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from vesremont_api import VesremontClient, ApiError
|
|
41
|
+
|
|
42
|
+
api = VesremontClient()
|
|
43
|
+
products = api.search("труборез", page=1, per_page=10)
|
|
44
|
+
product = api.product(375094)
|
|
45
|
+
draft = api.cart_draft(375094, 1)
|
|
46
|
+
# draft["share_url"] передаётся покупателю, не в публичные логи.
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`status`, `search`, `product`, `cart`, `cart_draft` — короткие помощники.
|
|
50
|
+
Остальные REST-операции: `request(method, '/path', query={}, body={}, idempotency_key=...)`.
|
|
51
|
+
Путь относительно `/api/v1`; GET вызывается без body. `filters` в query — JSON-строка.
|
|
52
|
+
Подборку можно дополнить через `cart_draft(..., draft=token)`; token берётся
|
|
53
|
+
из query `draft` ранее полученной share_url. Серверные схемы:
|
|
54
|
+
https://vesremont.com/openapi.json.
|
|
55
|
+
|
|
56
|
+
Для личных данных передайте уже полученный REST OAuth token:
|
|
57
|
+
`VesremontClient(token=token)`. OAuth-протокол и минимальные scopes описаны
|
|
58
|
+
в https://vesremont.com/llms/api.md. Браузерный OAuth мастер есть в Node CLI;
|
|
59
|
+
в Python SDK второй мастер не дублируется. Токен не пишется на диск, не входит в URL.
|
|
60
|
+
|
|
61
|
+
Timeout по умолчанию 15 секунд (параметр `timeout`, до 60). TLS проверяется,
|
|
62
|
+
redirects и автоматические повторы отсутствуют; API host фиксирован.
|
|
63
|
+
Ответ ограничен 2 MiB, тело запроса — 64 KiB.
|
|
64
|
+
`ApiError` содержит `status`, `code`, `request_id`, `retry_after`, без raw body.
|
|
65
|
+
После неопределённого исхода записи сначала перечитайте состояние.
|
|
66
|
+
Для submit нужны prepare, подтверждение покупателя на Vesremont и стабильный
|
|
67
|
+
`idempotency_key`; SDK не обходит эти проверки и не создаёт фиктивных заказов.
|
|
68
|
+
|
|
69
|
+
Используйте с внешнего ПК/хостинга. Это production API, sandbox не предоставляется.
|
|
70
|
+
Наличие SDK не означает включение отключённых операций или завершение приёмки.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
vesremont_api
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"""Vesremont REST client. Verified TLS, fixed origin, no redirects or retries."""
|
|
2
|
+
import json
|
|
3
|
+
import re
|
|
4
|
+
import ssl
|
|
5
|
+
from urllib.error import HTTPError, URLError
|
|
6
|
+
from urllib.parse import urlencode
|
|
7
|
+
from urllib.request import HTTPSHandler, HTTPRedirectHandler, Request, build_opener
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ApiError(Exception):
|
|
11
|
+
def __init__(self, status, code, request_id=None, retry_after=None):
|
|
12
|
+
super().__init__(f"Vesremont: {code} (HTTP {status})")
|
|
13
|
+
self.status, self.code = status, code
|
|
14
|
+
self.request_id, self.retry_after = request_id, retry_after
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class _NoRedirect(HTTPRedirectHandler):
|
|
18
|
+
def redirect_request(self, req, fp, code, msg, headers, newurl):
|
|
19
|
+
return None
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _safe(value):
|
|
23
|
+
return value if isinstance(value, str) and re.fullmatch(r"[A-Za-z0-9_.:-]{1,128}", value) else None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _id(value):
|
|
27
|
+
if type(value) is not int or not 1 <= value <= 2147483647:
|
|
28
|
+
raise ValueError("Positive product ID required")
|
|
29
|
+
return value
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class VesremontClient:
|
|
33
|
+
def __init__(self, token="", timeout=15):
|
|
34
|
+
if not isinstance(token, str) or (token and not re.fullmatch(r"[A-Za-z0-9_.~-]{1,8192}", token)):
|
|
35
|
+
raise ValueError("Invalid access token")
|
|
36
|
+
if type(timeout) not in (int, float) or not 0 < timeout <= 60:
|
|
37
|
+
raise ValueError("Timeout must be 0..60 seconds")
|
|
38
|
+
self._token, self._timeout = token, timeout
|
|
39
|
+
self._opener = build_opener(_NoRedirect(), HTTPSHandler(context=ssl.create_default_context()))
|
|
40
|
+
|
|
41
|
+
def request(self, method, path, *, query=None, body=None, idempotency_key=None):
|
|
42
|
+
if method not in ("GET", "POST", "PATCH", "DELETE") or not re.fullmatch(r"/[A-Za-z0-9_-]+(?:/[A-Za-z0-9_-]+)*/?", path):
|
|
43
|
+
raise ValueError("Invalid API method/path")
|
|
44
|
+
if body is not None and (method == "GET" or not isinstance(body, dict)):
|
|
45
|
+
raise ValueError("JSON object required; GET body is not supported")
|
|
46
|
+
if method == "POST" and path.rstrip("/") == "/orders/submit" and not idempotency_key:
|
|
47
|
+
raise ValueError("Idempotency-Key is required")
|
|
48
|
+
params = {}
|
|
49
|
+
for name, value in (query or {}).items():
|
|
50
|
+
if not re.fullmatch(r"[a-z_]{1,40}", name) or type(value) not in (str, int, float, bool):
|
|
51
|
+
raise ValueError("Query values must be scalar")
|
|
52
|
+
params[name] = str(value).lower() if type(value) is bool else str(value)
|
|
53
|
+
encoded = urlencode(params)
|
|
54
|
+
if len(encoded) > 8192:
|
|
55
|
+
raise ValueError("Query exceeds 8192 characters")
|
|
56
|
+
url = "https://vesremont.com/api/v1" + path + ("?" + encoded if encoded else "")
|
|
57
|
+
headers = {"Accept": "application/json", "User-Agent": "Vesremont-Python/0.2.0"}
|
|
58
|
+
if self._token:
|
|
59
|
+
headers["Authorization"] = "Bearer " + self._token
|
|
60
|
+
if idempotency_key is not None:
|
|
61
|
+
if not isinstance(idempotency_key, str) or not re.fullmatch(r"[A-Za-z0-9._:-]{16,128}", idempotency_key):
|
|
62
|
+
raise ValueError("Invalid idempotency key")
|
|
63
|
+
headers["Idempotency-Key"] = idempotency_key
|
|
64
|
+
payload = None if body is None else json.dumps(body, ensure_ascii=False, allow_nan=False).encode("utf-8")
|
|
65
|
+
if payload is not None:
|
|
66
|
+
if len(payload) > 65536:
|
|
67
|
+
raise ValueError("Request body exceeds 64 KiB")
|
|
68
|
+
headers["Content-Type"] = "application/json"
|
|
69
|
+
try:
|
|
70
|
+
try:
|
|
71
|
+
response = self._opener.open(Request(url, data=payload, headers=headers, method=method), timeout=self._timeout)
|
|
72
|
+
except HTTPError as error:
|
|
73
|
+
response = error
|
|
74
|
+
with response:
|
|
75
|
+
raw = response.read(2 * 1024 * 1024 + 1)
|
|
76
|
+
if len(raw) > 2 * 1024 * 1024:
|
|
77
|
+
raise ApiError(response.code, "response_too_large")
|
|
78
|
+
try:
|
|
79
|
+
data = json.loads(raw.decode("utf-8")) if raw else None
|
|
80
|
+
except (ValueError, UnicodeError):
|
|
81
|
+
raise ApiError(response.code, "invalid_json") from None
|
|
82
|
+
if not 200 <= response.code < 300:
|
|
83
|
+
problem = data if isinstance(data, dict) else {}
|
|
84
|
+
raise ApiError(response.code, _safe(problem.get("code")) or "http_error",
|
|
85
|
+
_safe(problem.get("request_id")), _safe(response.headers.get("Retry-After")))
|
|
86
|
+
return data
|
|
87
|
+
except (URLError, OSError):
|
|
88
|
+
raise ApiError(0, "transport_error") from None
|
|
89
|
+
|
|
90
|
+
def status(self):
|
|
91
|
+
return self.request("GET", "/status")
|
|
92
|
+
|
|
93
|
+
def search(self, q, **query):
|
|
94
|
+
return self.request("GET", "/products", query={**query, "q": q})
|
|
95
|
+
|
|
96
|
+
def product(self, product_id):
|
|
97
|
+
return self.request("GET", f"/products/{_id(product_id)}")
|
|
98
|
+
|
|
99
|
+
def cart(self):
|
|
100
|
+
return self.request("GET", "/cart")
|
|
101
|
+
|
|
102
|
+
def cart_draft(self, product_id, quantity=1, draft=None):
|
|
103
|
+
if type(quantity) is not int or not 1 <= quantity <= 99:
|
|
104
|
+
raise ValueError("Quantity must be 1..99")
|
|
105
|
+
query = {"product_id": _id(product_id), "quantity": quantity}
|
|
106
|
+
if draft is not None:
|
|
107
|
+
query["draft"] = draft
|
|
108
|
+
return self.request("GET", "/cart-drafts/", query=query)
|