makea-cli 0.1.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.
- makea_cli/__init__.py +1 -0
- makea_cli/__main__.py +6 -0
- makea_cli/api_client.py +376 -0
- makea_cli/auth_pkce.py +251 -0
- makea_cli/commands/__init__.py +23 -0
- makea_cli/commands/_util.py +16 -0
- makea_cli/commands/auth/__init__.py +3 -0
- makea_cli/commands/auth/cmd.py +41 -0
- makea_cli/commands/directory/__init__.py +3 -0
- makea_cli/commands/directory/cmd.py +39 -0
- makea_cli/commands/document/__init__.py +3 -0
- makea_cli/commands/document/cmd.py +182 -0
- makea_cli/commands/email/__init__.py +3 -0
- makea_cli/commands/email/cmd.py +122 -0
- makea_cli/commands/metrics/__init__.py +0 -0
- makea_cli/commands/metrics/cmd.py +98 -0
- makea_cli/commands/orders/__init__.py +3 -0
- makea_cli/commands/orders/cmd.py +202 -0
- makea_cli/commands/product/__init__.py +3 -0
- makea_cli/commands/product/cmd.py +160 -0
- makea_cli/commands/supplier/__init__.py +3 -0
- makea_cli/commands/supplier/cmd.py +305 -0
- makea_cli/config.py +74 -0
- makea_cli/main.py +29 -0
- makea_cli-0.1.1.dist-info/METADATA +98 -0
- makea_cli-0.1.1.dist-info/RECORD +28 -0
- makea_cli-0.1.1.dist-info/WHEEL +4 -0
- makea_cli-0.1.1.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
from rich.console import Console
|
|
5
|
+
|
|
6
|
+
from makea_cli.auth_pkce import login_and_save
|
|
7
|
+
from makea_cli.config import clear_credentials
|
|
8
|
+
|
|
9
|
+
console = Console()
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def register(app: typer.Typer) -> None:
|
|
13
|
+
@app.command(
|
|
14
|
+
"auth",
|
|
15
|
+
help="Browser login (Cognito); saves tokens locally, or --logout to clear.",
|
|
16
|
+
)
|
|
17
|
+
def auth(
|
|
18
|
+
logout: bool = typer.Option(
|
|
19
|
+
False,
|
|
20
|
+
"--logout",
|
|
21
|
+
help="Remove locally saved tokens and exit.",
|
|
22
|
+
),
|
|
23
|
+
) -> None:
|
|
24
|
+
"""
|
|
25
|
+
Sign in via Cognito Hosted UI in the browser and save tokens locally.
|
|
26
|
+
|
|
27
|
+
Input: optional --logout to clear saved credentials instead of logging in.
|
|
28
|
+
|
|
29
|
+
Output: on login, stores ID (and refresh when issued) token under the app config
|
|
30
|
+
directory; the Makea API accepts the ID token as Authorization: Bearer.
|
|
31
|
+
"""
|
|
32
|
+
if logout:
|
|
33
|
+
clear_credentials()
|
|
34
|
+
console.print("[green]已退出登录(本机保存的登录信息已清除)。[/green]")
|
|
35
|
+
raise typer.Exit(0)
|
|
36
|
+
try:
|
|
37
|
+
login_and_save()
|
|
38
|
+
except Exception as e:
|
|
39
|
+
console.print(f"[red]{e}[/red]")
|
|
40
|
+
raise typer.Exit(1) from e
|
|
41
|
+
console.print("[green]登录成功,已保存在本机。[/green]")
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
from rich.console import Console
|
|
5
|
+
|
|
6
|
+
from makea_cli import api_client
|
|
7
|
+
from makea_cli.commands._util import print_json_or_exit
|
|
8
|
+
|
|
9
|
+
console = Console()
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def register(app: typer.Typer) -> None:
|
|
13
|
+
@app.command(
|
|
14
|
+
"list-users",
|
|
15
|
+
help="GET /admin/users — list registered users (admin, optional pagination).",
|
|
16
|
+
)
|
|
17
|
+
def list_users(
|
|
18
|
+
limit: int | None = typer.Option(
|
|
19
|
+
None,
|
|
20
|
+
"--limit",
|
|
21
|
+
"-n",
|
|
22
|
+
help="Optional page size (omit for one full response per server rules).",
|
|
23
|
+
),
|
|
24
|
+
offset: int = typer.Option(
|
|
25
|
+
0,
|
|
26
|
+
"--offset",
|
|
27
|
+
help="Pagination offset (used with --limit).",
|
|
28
|
+
),
|
|
29
|
+
) -> None:
|
|
30
|
+
"""
|
|
31
|
+
List registered users (admin).
|
|
32
|
+
|
|
33
|
+
Input: optional --limit / --offset for pagination (GET /admin/users query params).
|
|
34
|
+
|
|
35
|
+
Output: JSON body from the API (typically success, result, pagination when limited).
|
|
36
|
+
"""
|
|
37
|
+
print_json_or_exit(
|
|
38
|
+
console, lambda: api_client.get_all_users(limit=limit, offset=offset)
|
|
39
|
+
)
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
from rich.console import Console
|
|
8
|
+
|
|
9
|
+
from makea_cli import api_client
|
|
10
|
+
|
|
11
|
+
console = Console()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _write_downloaded_file(
|
|
15
|
+
data: bytes,
|
|
16
|
+
*,
|
|
17
|
+
suggested: str | None,
|
|
18
|
+
fallback_name: str,
|
|
19
|
+
output: Path | None,
|
|
20
|
+
) -> None:
|
|
21
|
+
out_path = output
|
|
22
|
+
if out_path is None:
|
|
23
|
+
out_path = Path.cwd() / (suggested or fallback_name)
|
|
24
|
+
out_path.write_bytes(data)
|
|
25
|
+
console.print(f"Wrote [green]{out_path.resolve()}[/green] ({len(data)} bytes)")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def register(app: typer.Typer) -> None:
|
|
29
|
+
@app.command(
|
|
30
|
+
"download-document",
|
|
31
|
+
help=(
|
|
32
|
+
"GET /admin/document/download — save a document file "
|
|
33
|
+
"(document id + designer user_id)."
|
|
34
|
+
),
|
|
35
|
+
)
|
|
36
|
+
def download_document(
|
|
37
|
+
document_id: str = typer.Argument(
|
|
38
|
+
...,
|
|
39
|
+
help="Document id (same as document reference id / UUID in Dynamo).",
|
|
40
|
+
),
|
|
41
|
+
user_id: str = typer.Option(
|
|
42
|
+
...,
|
|
43
|
+
"--user-id",
|
|
44
|
+
"-u",
|
|
45
|
+
help="Designer user id (document owner); required by the API query string.",
|
|
46
|
+
),
|
|
47
|
+
output: Path | None = typer.Option(
|
|
48
|
+
None,
|
|
49
|
+
"--output",
|
|
50
|
+
"-o",
|
|
51
|
+
help=(
|
|
52
|
+
"Output path. Default: current directory + filename from "
|
|
53
|
+
"Content-Disposition, or document_id if missing."
|
|
54
|
+
),
|
|
55
|
+
),
|
|
56
|
+
timeout: float = typer.Option(
|
|
57
|
+
120.0,
|
|
58
|
+
"--timeout",
|
|
59
|
+
"-t",
|
|
60
|
+
help="HTTP timeout in seconds.",
|
|
61
|
+
min=10.0,
|
|
62
|
+
max=3600.0,
|
|
63
|
+
),
|
|
64
|
+
) -> None:
|
|
65
|
+
"""
|
|
66
|
+
Calls the same admin endpoint as the web app: **GET /admin/document/download**
|
|
67
|
+
with query parameters ``user_id`` and ``document_id``.
|
|
68
|
+
|
|
69
|
+
The backend may return a file body or redirect to a presigned URL; the client
|
|
70
|
+
follows redirects and writes the final bytes to disk.
|
|
71
|
+
"""
|
|
72
|
+
try:
|
|
73
|
+
data, suggested = api_client.download_admin_document(
|
|
74
|
+
user_id=user_id,
|
|
75
|
+
document_id=document_id,
|
|
76
|
+
timeout=timeout,
|
|
77
|
+
)
|
|
78
|
+
except Exception as e:
|
|
79
|
+
console.print(f"[red]{e}[/red]")
|
|
80
|
+
raise typer.Exit(1) from e
|
|
81
|
+
|
|
82
|
+
_write_downloaded_file(
|
|
83
|
+
data, suggested=suggested, fallback_name=document_id, output=output
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
@app.command(
|
|
87
|
+
"download-product-document",
|
|
88
|
+
help=(
|
|
89
|
+
"Resolve product via list-product-orders payload, then GET /admin/document/download."
|
|
90
|
+
),
|
|
91
|
+
)
|
|
92
|
+
def download_product_document(
|
|
93
|
+
product_reference_id: str = typer.Argument(
|
|
94
|
+
...,
|
|
95
|
+
help="Product ``reference_id`` (or ``product_id``) as in list-product-orders JSON.",
|
|
96
|
+
),
|
|
97
|
+
document_id: str = typer.Argument(
|
|
98
|
+
...,
|
|
99
|
+
help="``document_id`` from that product's ``available_documents`` entry.",
|
|
100
|
+
),
|
|
101
|
+
designer_user_id: str = typer.Option(
|
|
102
|
+
...,
|
|
103
|
+
"--designer-user-id",
|
|
104
|
+
"-d",
|
|
105
|
+
help=(
|
|
106
|
+
"Designer Cognito ``user_id``. Command uses per-user product-order API; "
|
|
107
|
+
"no global list scan."
|
|
108
|
+
),
|
|
109
|
+
),
|
|
110
|
+
output: Path | None = typer.Option(
|
|
111
|
+
None,
|
|
112
|
+
"--output",
|
|
113
|
+
"-o",
|
|
114
|
+
help="Output path (default: cwd + Content-Disposition name or document_id).",
|
|
115
|
+
),
|
|
116
|
+
timeout: float = typer.Option(
|
|
117
|
+
120.0,
|
|
118
|
+
"--timeout",
|
|
119
|
+
"-t",
|
|
120
|
+
help="HTTP timeout in seconds.",
|
|
121
|
+
min=10.0,
|
|
122
|
+
max=3600.0,
|
|
123
|
+
),
|
|
124
|
+
) -> None:
|
|
125
|
+
"""
|
|
126
|
+
**Metadata source:** ``list-product-orders`` (and the per-user variant) already returns
|
|
127
|
+
``user_id`` and each document's ``document_id`` under ``available_documents`` — no extra
|
|
128
|
+
metadata endpoint is required for this flow.
|
|
129
|
+
|
|
130
|
+
This command fetches one designer's product-order list, finds the product row,
|
|
131
|
+
checks the document exists, picks the correct ``user_id`` for the download query
|
|
132
|
+
(admin uploads use ``admin_user_id`` when present), then downloads the file.
|
|
133
|
+
"""
|
|
134
|
+
payload = api_client.get_product_orders_by_user(designer_user_id)
|
|
135
|
+
product: dict[str, Any] | None = None
|
|
136
|
+
for row in payload.get("result") or []:
|
|
137
|
+
if (
|
|
138
|
+
isinstance(row, dict)
|
|
139
|
+
and (
|
|
140
|
+
row.get("reference_id") == product_reference_id
|
|
141
|
+
or row.get("product_id") == product_reference_id
|
|
142
|
+
)
|
|
143
|
+
):
|
|
144
|
+
product = row
|
|
145
|
+
break
|
|
146
|
+
if not product:
|
|
147
|
+
console.print(
|
|
148
|
+
"[red]Product not found in this designer's product orders.[/red]"
|
|
149
|
+
)
|
|
150
|
+
raise typer.Exit(1)
|
|
151
|
+
|
|
152
|
+
doc_entry: dict[str, Any] | None = None
|
|
153
|
+
for raw in product.get("available_documents") or []:
|
|
154
|
+
if isinstance(raw, dict) and raw.get("document_id") == document_id:
|
|
155
|
+
doc_entry = raw
|
|
156
|
+
break
|
|
157
|
+
if not doc_entry:
|
|
158
|
+
console.print(
|
|
159
|
+
"[red]document_id not found on this product's available_documents.[/red]"
|
|
160
|
+
)
|
|
161
|
+
raise typer.Exit(1)
|
|
162
|
+
|
|
163
|
+
download_uid = api_client.effective_user_id_for_document_download(
|
|
164
|
+
product, doc_entry
|
|
165
|
+
)
|
|
166
|
+
if not download_uid:
|
|
167
|
+
console.print("[red]Could not determine user_id for download.[/red]")
|
|
168
|
+
raise typer.Exit(1)
|
|
169
|
+
|
|
170
|
+
try:
|
|
171
|
+
data, suggested = api_client.download_admin_document(
|
|
172
|
+
user_id=download_uid,
|
|
173
|
+
document_id=document_id,
|
|
174
|
+
timeout=timeout,
|
|
175
|
+
)
|
|
176
|
+
except Exception as e:
|
|
177
|
+
console.print(f"[red]{e}[/red]")
|
|
178
|
+
raise typer.Exit(1) from e
|
|
179
|
+
|
|
180
|
+
_write_downloaded_file(
|
|
181
|
+
data, suggested=suggested, fallback_name=document_id, output=output
|
|
182
|
+
)
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Annotated
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
|
|
10
|
+
from makea_cli import api_client
|
|
11
|
+
from makea_cli.commands._util import print_json_or_exit
|
|
12
|
+
|
|
13
|
+
console = Console()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def register(app: typer.Typer) -> None:
|
|
17
|
+
@app.command(
|
|
18
|
+
"send-email",
|
|
19
|
+
help=(
|
|
20
|
+
"POST /admin/email/send — queue an HTML email (To required, Cc optional). "
|
|
21
|
+
"From must be @makea.co; HTML from --html-file or stdin ('-'). "
|
|
22
|
+
"Requires admin login (makea-cli auth)."
|
|
23
|
+
),
|
|
24
|
+
)
|
|
25
|
+
def send_email(
|
|
26
|
+
from_email: str = typer.Option(
|
|
27
|
+
...,
|
|
28
|
+
"--from",
|
|
29
|
+
help="Envelope From (must be @makea.co; supports 'Name <addr@makea.co>').",
|
|
30
|
+
),
|
|
31
|
+
subject: str = typer.Option(
|
|
32
|
+
...,
|
|
33
|
+
"--subject",
|
|
34
|
+
"-s",
|
|
35
|
+
help="Email Subject header.",
|
|
36
|
+
),
|
|
37
|
+
to: Annotated[
|
|
38
|
+
list[str],
|
|
39
|
+
typer.Option(
|
|
40
|
+
"--to",
|
|
41
|
+
"-t",
|
|
42
|
+
help="To recipient (repeat per address). At least one required.",
|
|
43
|
+
),
|
|
44
|
+
] = [],
|
|
45
|
+
cc: Annotated[
|
|
46
|
+
list[str],
|
|
47
|
+
typer.Option(
|
|
48
|
+
"--cc",
|
|
49
|
+
"-c",
|
|
50
|
+
help="Cc recipient (repeat per address). Optional; omitted if unused.",
|
|
51
|
+
),
|
|
52
|
+
] = [],
|
|
53
|
+
html_file: Path | None = typer.Option(
|
|
54
|
+
None,
|
|
55
|
+
"--html-file",
|
|
56
|
+
"-f",
|
|
57
|
+
exists=False,
|
|
58
|
+
dir_okay=False,
|
|
59
|
+
help="UTF-8 HTML body file, or '-' to read HTML from stdin.",
|
|
60
|
+
),
|
|
61
|
+
text: str | None = typer.Option(
|
|
62
|
+
None,
|
|
63
|
+
"--text",
|
|
64
|
+
help="Optional plain-text part (MIME alternative); if omitted, server derives from HTML.",
|
|
65
|
+
),
|
|
66
|
+
) -> None:
|
|
67
|
+
"""
|
|
68
|
+
Queue an HTML email through ``POST /admin/email/send``.
|
|
69
|
+
|
|
70
|
+
**To** is required (``--to`` / ``-t``, repeat for multiple). **Cc** is optional
|
|
71
|
+
(``--cc`` / ``-c``). The API drops any Cc address that duplicates a To address.
|
|
72
|
+
|
|
73
|
+
**From** must use the ``makea.co`` domain. **HTML** comes from ``--html-file``
|
|
74
|
+
or from stdin when ``-f -``.
|
|
75
|
+
|
|
76
|
+
**Auth:** run ``makea-cli auth`` first with an admin account.
|
|
77
|
+
|
|
78
|
+
**Examples**::
|
|
79
|
+
|
|
80
|
+
makea-cli send-email --from noreply@makea.co -s "Hello" \\
|
|
81
|
+
-t one@example.com -t two@example.com -f ./body.html
|
|
82
|
+
|
|
83
|
+
makea-cli send-email --from alerts@makea.co -s "FYI" \\
|
|
84
|
+
-t lead@example.com --cc manager@example.com -f ./news.html
|
|
85
|
+
|
|
86
|
+
cat body.html | makea-cli send-email --from noreply@makea.co -s "Hi" \\
|
|
87
|
+
-t user@example.com -f -
|
|
88
|
+
"""
|
|
89
|
+
if not to:
|
|
90
|
+
console.print("[red]Provide at least one --to recipient.[/red]")
|
|
91
|
+
raise typer.Exit(1)
|
|
92
|
+
|
|
93
|
+
if html_file is None:
|
|
94
|
+
console.print("[red]Provide --html-file (use '-' for stdin).[/red]")
|
|
95
|
+
raise typer.Exit(1)
|
|
96
|
+
|
|
97
|
+
p = html_file.expanduser()
|
|
98
|
+
if str(p) == "-":
|
|
99
|
+
html = sys.stdin.read()
|
|
100
|
+
else:
|
|
101
|
+
if not p.is_file():
|
|
102
|
+
console.print(f"[red]Not a file: {p}[/red]")
|
|
103
|
+
raise typer.Exit(1)
|
|
104
|
+
html = p.read_text(encoding="utf-8")
|
|
105
|
+
|
|
106
|
+
if not html.strip():
|
|
107
|
+
console.print("[red]HTML body is empty.[/red]")
|
|
108
|
+
raise typer.Exit(1)
|
|
109
|
+
|
|
110
|
+
body: dict[str, str | list[str]] = {
|
|
111
|
+
"from": from_email.strip(),
|
|
112
|
+
"to": [x.strip() for x in to if x.strip()],
|
|
113
|
+
"subject": subject.strip(),
|
|
114
|
+
"html": html,
|
|
115
|
+
}
|
|
116
|
+
cc_addrs = [x.strip() for x in cc if x.strip()]
|
|
117
|
+
if cc_addrs:
|
|
118
|
+
body["cc"] = cc_addrs
|
|
119
|
+
if text is not None and text.strip():
|
|
120
|
+
body["text"] = text.strip()
|
|
121
|
+
|
|
122
|
+
print_json_or_exit(console, lambda: api_client.send_admin_raw_email(body))
|
|
File without changes
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
from rich.console import Console
|
|
5
|
+
|
|
6
|
+
from makea_cli import api_client
|
|
7
|
+
from makea_cli.commands._util import print_json_or_exit
|
|
8
|
+
|
|
9
|
+
console = Console()
|
|
10
|
+
|
|
11
|
+
_GRANULARITIES = ("day", "week", "month")
|
|
12
|
+
_ORDER_TYPES = ("all", "sampling", "production")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def register(app: typer.Typer) -> None:
|
|
16
|
+
@app.command(
|
|
17
|
+
"get-cumulative-payment-and-platform-revenue",
|
|
18
|
+
help=(
|
|
19
|
+
"GET /admin/business-metrics/cumulative-payment-and-platform-revenue — "
|
|
20
|
+
"platform-wide payment received and platform revenue (service fee + "
|
|
21
|
+
"transaction fee) bucketed over a date range."
|
|
22
|
+
),
|
|
23
|
+
)
|
|
24
|
+
def get_cumulative_payment_and_platform_revenue(
|
|
25
|
+
start_date: str = typer.Option(
|
|
26
|
+
...,
|
|
27
|
+
"--start-date",
|
|
28
|
+
help="Start date (inclusive), ISO format YYYY-MM-DD.",
|
|
29
|
+
),
|
|
30
|
+
end_date: str = typer.Option(
|
|
31
|
+
...,
|
|
32
|
+
"--end-date",
|
|
33
|
+
help="End date (inclusive), ISO format YYYY-MM-DD.",
|
|
34
|
+
),
|
|
35
|
+
granularity: str = typer.Option(
|
|
36
|
+
"day",
|
|
37
|
+
"--granularity",
|
|
38
|
+
"-g",
|
|
39
|
+
help="Time bucket: day, week, or month. Default: day.",
|
|
40
|
+
),
|
|
41
|
+
currency: str = typer.Option(
|
|
42
|
+
"GBP",
|
|
43
|
+
"--currency",
|
|
44
|
+
"-c",
|
|
45
|
+
help="Target currency for conversion. Default: GBP.",
|
|
46
|
+
),
|
|
47
|
+
order_type: str = typer.Option(
|
|
48
|
+
"all",
|
|
49
|
+
"--order-type",
|
|
50
|
+
"-t",
|
|
51
|
+
help="Filter: all, sampling, or production. Default: all.",
|
|
52
|
+
),
|
|
53
|
+
) -> None:
|
|
54
|
+
"""
|
|
55
|
+
Platform-wide cumulative payment received and platform revenue over a date range.
|
|
56
|
+
|
|
57
|
+
Calls GET /admin/business-metrics/cumulative-payment-and-platform-revenue.
|
|
58
|
+
|
|
59
|
+
Platform revenue = service fee + transaction fee (the 2.8% transaction fee is
|
|
60
|
+
applied by the server). The response contains two siblings under ``result``:
|
|
61
|
+
|
|
62
|
+
- ``payment_received``: cumulative/period amounts per bucket, plus a
|
|
63
|
+
``payment_breakdown`` (sampling / production_deposit / production_final).
|
|
64
|
+
- ``platform_revenue``: cumulative/period amounts per bucket.
|
|
65
|
+
|
|
66
|
+
Input: required --start-date and --end-date (YYYY-MM-DD); optional
|
|
67
|
+
--granularity (day|week|month), --currency, --order-type (all|sampling|production).
|
|
68
|
+
|
|
69
|
+
Output: raw JSON body from the admin business-metrics endpoint.
|
|
70
|
+
|
|
71
|
+
This endpoint is **platform-wide only** and does not support filtering by
|
|
72
|
+
user_id, product, or category. For per-user / per-product drill-downs, use
|
|
73
|
+
list-product-orders / list-sampling-orders-by-product /
|
|
74
|
+
list-production-orders-by-product and aggregate client-side.
|
|
75
|
+
"""
|
|
76
|
+
g = granularity.strip().lower()
|
|
77
|
+
if g not in _GRANULARITIES:
|
|
78
|
+
console.print(
|
|
79
|
+
f"[red]--granularity must be one of: {', '.join(_GRANULARITIES)}.[/red]"
|
|
80
|
+
)
|
|
81
|
+
raise typer.Exit(1)
|
|
82
|
+
ot = order_type.strip().lower()
|
|
83
|
+
if ot not in _ORDER_TYPES:
|
|
84
|
+
console.print(
|
|
85
|
+
f"[red]--order-type must be one of: {', '.join(_ORDER_TYPES)}.[/red]"
|
|
86
|
+
)
|
|
87
|
+
raise typer.Exit(1)
|
|
88
|
+
|
|
89
|
+
print_json_or_exit(
|
|
90
|
+
console,
|
|
91
|
+
lambda: api_client.get_cumulative_payment_and_platform_revenue(
|
|
92
|
+
start_date=start_date,
|
|
93
|
+
end_date=end_date,
|
|
94
|
+
granularity=g,
|
|
95
|
+
currency=currency,
|
|
96
|
+
order_type=ot,
|
|
97
|
+
),
|
|
98
|
+
)
|