mcm-cli 1.2.0__tar.gz → 1.3.1__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {mcm_cli-1.2.0/mcm_cli.egg-info → mcm_cli-1.3.1}/PKG-INFO +1 -1
- {mcm_cli-1.2.0 → mcm_cli-1.3.1/mcm_cli.egg-info}/PKG-INFO +1 -1
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/__main__.py +1 -1
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/command/wallet.py +83 -19
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/data/wallet.py +43 -0
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/requests.py +8 -0
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/setup.py +1 -1
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/LICENSE +0 -0
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/NOTICE +0 -0
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/README.md +0 -0
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcm_cli.egg-info/SOURCES.txt +0 -0
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcm_cli.egg-info/dependency_links.txt +0 -0
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcm_cli.egg-info/entry_points.txt +0 -0
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcm_cli.egg-info/requires.txt +0 -0
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcm_cli.egg-info/top_level.txt +0 -0
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/__init__.py +0 -0
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/command/account.py +0 -0
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/command/admin.py +0 -0
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/command/auth.py +0 -0
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/command/config.py +0 -0
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/command/decision.py +0 -0
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/data/account.py +0 -0
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/data/account_user.py +0 -0
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/data/decision.py +0 -0
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/data/error.py +0 -0
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/data/item.py +0 -0
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/data/seller.py +0 -0
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/data/token.py +0 -0
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/logging.py +0 -0
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/setup.cfg +0 -0
- {mcm_cli-1.2.0 → mcm_cli-1.3.1}/tests/test_config.py +0 -0
@@ -35,7 +35,7 @@ def version():
|
|
35
35
|
"""
|
36
36
|
Show the tool version
|
37
37
|
"""
|
38
|
-
typer.echo(f"Version: mcm-cli v1.
|
38
|
+
typer.echo(f"Version: mcm-cli v1.3.1")
|
39
39
|
|
40
40
|
app.add_typer(mcmcli.command.account.app, name="account", help="Ad account management")
|
41
41
|
app.add_typer(mcmcli.command.admin.app, name="admin", help="Platform administration")
|
@@ -12,9 +12,10 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
+
from datetime import datetime
|
15
16
|
from enum import Enum
|
16
17
|
from mcmcli.data.error import Error
|
17
|
-
from mcmcli.data.wallet import Wallet, WalletsWrapper
|
18
|
+
from mcmcli.data.wallet import Wallet, WalletsWrapper, PlatformWalletsWrapper
|
18
19
|
from mcmcli.requests import CurlString, api_request
|
19
20
|
|
20
21
|
import json
|
@@ -36,20 +37,68 @@ class OperationType(Enum):
|
|
36
37
|
DEPOSIT = "deposit"
|
37
38
|
WITHDRAW = "withdraw"
|
38
39
|
|
40
|
+
def _get_wallet_balance(wallet: Wallet):
|
41
|
+
wa0 = wallet.accounts[0]
|
42
|
+
wa1 = wallet.accounts[1]
|
43
|
+
|
44
|
+
credits_amount_micro = wa0.balance.amount_micro if wa0.type == 'CREDITS' else wa1.balance.amount_micro
|
45
|
+
pre_paid_amount_micro = wa0.balance.amount_micro if wa0.type == 'PRE_PAID' else wa1.balance.amount_micro
|
46
|
+
credit_balance = float(credits_amount_micro) / float(1000000)
|
47
|
+
prepaid_balance = float(pre_paid_amount_micro) / float(1000000)
|
48
|
+
|
49
|
+
return (credit_balance, prepaid_balance)
|
50
|
+
|
51
|
+
|
52
|
+
@app.command()
|
53
|
+
def platform_balance(
|
54
|
+
to_curl: bool = typer.Option(False, help="Generate the curl command instead of executing it."),
|
55
|
+
profile: str = typer.Option("default", help="profile name of the MCM CLI."),
|
56
|
+
):
|
57
|
+
"""
|
58
|
+
Get the current balances of all ad accounts in CSV format.
|
59
|
+
"""
|
60
|
+
auth = mcmcli.command.auth.AuthCommand(profile)
|
61
|
+
curl, error, token = auth.get_token()
|
62
|
+
if error:
|
63
|
+
print(f"ERROR: {error.message}", file=sys.stderr, flush=True)
|
64
|
+
return
|
65
|
+
|
66
|
+
# Get current UTC timestamp and format it as an ISO 8601 string with microseconds
|
67
|
+
current_timestamp = datetime.utcnow().isoformat(timespec='microseconds') + "Z"
|
68
|
+
|
69
|
+
wc = WalletCommand(profile, auth, token.token)
|
70
|
+
curl, error, platform_wallets = wc.get_platform_balance(to_curl)
|
71
|
+
if to_curl:
|
72
|
+
print(curl)
|
73
|
+
return
|
74
|
+
if error:
|
75
|
+
print(f"ERROR: {error.message}", file=sys.stderr, flush=True)
|
76
|
+
return
|
77
|
+
if platform_wallets is None:
|
78
|
+
print(f"ERROR: Cannot find the wallets", file=sys.stderr, flush=True)
|
79
|
+
return
|
80
|
+
|
81
|
+
print("ad_account_id,credit_balance,prepaid_balance,got_balance_info_at_utc")
|
82
|
+
for account_id, account_data in platform_wallets.items():
|
83
|
+
wallet = account_data.wallets[0]
|
84
|
+
credit_balance, prepaid_balance = _get_wallet_balance(wallet)
|
85
|
+
print(f'{account_id},{credit_balance},{prepaid_balance},{current_timestamp}')
|
86
|
+
|
87
|
+
|
39
88
|
@app.command()
|
40
89
|
def balance(
|
41
90
|
account_id: str = typer.Option(help="Ad account ID"),
|
42
91
|
to_curl: bool = typer.Option(False, help="Generate the curl command instead of executing it."),
|
43
92
|
to_json: bool = typer.Option(False, help="Print raw output in json"),
|
44
|
-
profile: str = "default",
|
45
|
-
|
93
|
+
profile: str = typer.Option("default", help="profile name of the MCM CLI."),
|
94
|
+
):
|
46
95
|
"""
|
47
96
|
Retrive the current balance of the given ad account's wallet.
|
48
97
|
"""
|
49
98
|
auth = mcmcli.command.auth.AuthCommand(profile)
|
50
99
|
curl, error, token = auth.get_token()
|
51
100
|
if error:
|
52
|
-
print(f"ERROR: {error.message}")
|
101
|
+
print(f"ERROR: {error.message}", file=sys.stderr, flush=True)
|
53
102
|
return
|
54
103
|
|
55
104
|
wc = WalletCommand(profile, auth, token.token)
|
@@ -58,24 +107,20 @@ def balance(
|
|
58
107
|
print(curl)
|
59
108
|
return
|
60
109
|
if error:
|
61
|
-
print(f"ERROR: {error.message}")
|
110
|
+
print(f"ERROR: {error.message}", file=sys.stderr, flush=True)
|
111
|
+
return
|
112
|
+
if wallet is None:
|
113
|
+
print(f"ERROR: Wallet does not exist.", file=sys.stderr, flush=True)
|
62
114
|
return
|
63
115
|
if to_json:
|
64
116
|
print(wallet.model_dump_json())
|
65
117
|
return
|
66
118
|
|
67
|
-
|
68
|
-
wa1 = wallet.accounts[1]
|
69
|
-
|
70
|
-
credits_amount_micro = wa0.balance.amount_micro if wa0.type == 'CREDITS' else wa1.balance.amount_micro
|
71
|
-
pre_paid_amount_micro = wa0.balance.amount_micro if wa0.type == 'PRE_PAID' else wa1.balance.amount_micro
|
72
|
-
credit_amount = float(credits_amount_micro) / float(1000000)
|
73
|
-
money_amount = float(pre_paid_amount_micro) / float(1000000)
|
119
|
+
credit_balance, prepaid_balance = _get_wallet_balance(wallet)
|
74
120
|
|
75
121
|
print(f"Ad account ID = {account_id}")
|
76
|
-
print(f"
|
77
|
-
print(f"PRE_PAID balance = {
|
78
|
-
print(f"CREDITS balance = {credit_amount}")
|
122
|
+
print(f"CREDITS balance = {credit_balance}")
|
123
|
+
print(f"PRE_PAID balance = {prepaid_balance}")
|
79
124
|
return
|
80
125
|
|
81
126
|
|
@@ -86,8 +131,8 @@ def deposit(
|
|
86
131
|
fund_amount: float = typer.Option(help="The fund amount to deposit"),
|
87
132
|
to_curl: bool = typer.Option(False, help="Generate the curl command instead of executing it."),
|
88
133
|
to_json: bool = typer.Option(False, help="Print raw output in json"),
|
89
|
-
profile: str = "default",
|
90
|
-
|
134
|
+
profile: str = typer.Option("default", help="profile name of the MCM CLI."),
|
135
|
+
):
|
91
136
|
"""
|
92
137
|
Add or top up the money amount to the current balance of the given ad account's wallet.
|
93
138
|
"""
|
@@ -137,8 +182,8 @@ def withdraw(
|
|
137
182
|
fund_amount: float = typer.Option(help="The amount of credit to add"),
|
138
183
|
to_curl: bool = typer.Option(False, help="Generate the curl command instead of executing it."),
|
139
184
|
to_json: bool = typer.Option(False, help="Print raw output in json"),
|
140
|
-
profile: str = "default",
|
141
|
-
|
185
|
+
profile: str = typer.Option("default", help="profile name of the MCM CLI."),
|
186
|
+
):
|
142
187
|
"""
|
143
188
|
Withdraws the money amount from the current balance of the given ad account's wallet.
|
144
189
|
"""
|
@@ -202,6 +247,25 @@ class WalletCommand:
|
|
202
247
|
"Authorization": f"Bearer {token}"
|
203
248
|
}
|
204
249
|
|
250
|
+
def get_platform_balance(
|
251
|
+
self,
|
252
|
+
to_curl: bool,
|
253
|
+
) -> tuple[
|
254
|
+
None | CurlString,
|
255
|
+
None | Error,
|
256
|
+
None | dict[str, WalletsWrapper]
|
257
|
+
]:
|
258
|
+
_api_url = f"{self.api_base_url}/wallets-bulk/read"
|
259
|
+
|
260
|
+
curl, error, json_obj = api_request('POST', to_curl, _api_url, self.headers)
|
261
|
+
if curl:
|
262
|
+
return curl, None, None
|
263
|
+
if error:
|
264
|
+
return None, error, None
|
265
|
+
|
266
|
+
platform_wallets_wrapper = PlatformWalletsWrapper(**json_obj)
|
267
|
+
return None, None, platform_wallets_wrapper.result
|
268
|
+
|
205
269
|
|
206
270
|
def get_balance(
|
207
271
|
self,
|
@@ -67,3 +67,46 @@ class Wallet(BaseModel):
|
|
67
67
|
|
68
68
|
class WalletsWrapper(BaseModel):
|
69
69
|
wallets: list[Wallet]
|
70
|
+
|
71
|
+
|
72
|
+
#
|
73
|
+
# API response dataclasses for the platform balance API responses
|
74
|
+
#
|
75
|
+
#
|
76
|
+
# {
|
77
|
+
# "result": {
|
78
|
+
# "10054": {
|
79
|
+
# "wallets": [
|
80
|
+
# {
|
81
|
+
# "id": "wRydQ9MhQx4ZyJED",
|
82
|
+
# "title": "",
|
83
|
+
# "ad_account_id": "10054",
|
84
|
+
# "type": "PRE_PAYMENT",
|
85
|
+
# "accounts": [
|
86
|
+
# {
|
87
|
+
# "type": "CREDITS",
|
88
|
+
# "balance": {
|
89
|
+
# "currency": "USD",
|
90
|
+
# "amount_micro": "1890020000"
|
91
|
+
# }
|
92
|
+
# },
|
93
|
+
# {
|
94
|
+
# "type": "PRE_PAID",
|
95
|
+
# "balance": {
|
96
|
+
# "currency": "USD",
|
97
|
+
# "amount_micro": "0"
|
98
|
+
# }
|
99
|
+
# }
|
100
|
+
# ],
|
101
|
+
# "created_at": "2024-09-24T17:26:09.437580Z",
|
102
|
+
# "updated_at": "2024-10-20T22:00:21.412482Z"
|
103
|
+
# }
|
104
|
+
# ]
|
105
|
+
# }
|
106
|
+
# }
|
107
|
+
# }
|
108
|
+
|
109
|
+
class PlatformWalletsWrapper(BaseModel):
|
110
|
+
result: dict[str, WalletsWrapper] # Dictionary with ad_account_id as keys
|
111
|
+
|
112
|
+
|
@@ -38,6 +38,8 @@ def get(url, headers):
|
|
38
38
|
try:
|
39
39
|
res = requests.get(url, headers=headers)
|
40
40
|
return None, json.loads(res.text)
|
41
|
+
except json.JSONDecodeError:
|
42
|
+
return Error(code=0, message=res.text), None
|
41
43
|
except Exception as e:
|
42
44
|
return e, None
|
43
45
|
|
@@ -46,6 +48,8 @@ def delete(url, headers):
|
|
46
48
|
try:
|
47
49
|
res = requests.delete(url, headers=headers)
|
48
50
|
return None, json.loads(res.text)
|
51
|
+
except json.JSONDecodeError:
|
52
|
+
return Error(code=0, message=res.text), None
|
49
53
|
except Exception as e:
|
50
54
|
return e, None
|
51
55
|
|
@@ -54,6 +58,8 @@ def post(url, headers, payload):
|
|
54
58
|
try:
|
55
59
|
res = requests.post(url, headers=headers, json=payload)
|
56
60
|
return None, json.loads(res.text)
|
61
|
+
except json.JSONDecodeError:
|
62
|
+
return Error(code=0, message=res.text), None
|
57
63
|
except Exception as e:
|
58
64
|
return e, None
|
59
65
|
|
@@ -61,6 +67,8 @@ def put(url, headers, payload):
|
|
61
67
|
try:
|
62
68
|
res = requests.put(url, headers=headers, json=payload)
|
63
69
|
return None, json.loads(res.text)
|
70
|
+
except json.JSONDecodeError:
|
71
|
+
return Error(code=0, message=res.text), None
|
64
72
|
except Exception as e:
|
65
73
|
return e, None
|
66
74
|
|
@@ -18,7 +18,7 @@ from setuptools import setup, find_packages
|
|
18
18
|
|
19
19
|
setup(
|
20
20
|
name='mcm-cli',
|
21
|
-
version='1.
|
21
|
+
version='1.3.1',
|
22
22
|
description='A command-line interface for Moloco Commerde Media',
|
23
23
|
long_description=open('README.md').read(),
|
24
24
|
long_description_content_type='text/markdown',
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|