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.
Files changed (31) hide show
  1. {mcm_cli-1.2.0/mcm_cli.egg-info → mcm_cli-1.3.1}/PKG-INFO +1 -1
  2. {mcm_cli-1.2.0 → mcm_cli-1.3.1/mcm_cli.egg-info}/PKG-INFO +1 -1
  3. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/__main__.py +1 -1
  4. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/command/wallet.py +83 -19
  5. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/data/wallet.py +43 -0
  6. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/requests.py +8 -0
  7. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/setup.py +1 -1
  8. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/LICENSE +0 -0
  9. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/NOTICE +0 -0
  10. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/README.md +0 -0
  11. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcm_cli.egg-info/SOURCES.txt +0 -0
  12. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcm_cli.egg-info/dependency_links.txt +0 -0
  13. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcm_cli.egg-info/entry_points.txt +0 -0
  14. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcm_cli.egg-info/requires.txt +0 -0
  15. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcm_cli.egg-info/top_level.txt +0 -0
  16. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/__init__.py +0 -0
  17. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/command/account.py +0 -0
  18. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/command/admin.py +0 -0
  19. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/command/auth.py +0 -0
  20. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/command/config.py +0 -0
  21. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/command/decision.py +0 -0
  22. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/data/account.py +0 -0
  23. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/data/account_user.py +0 -0
  24. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/data/decision.py +0 -0
  25. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/data/error.py +0 -0
  26. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/data/item.py +0 -0
  27. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/data/seller.py +0 -0
  28. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/data/token.py +0 -0
  29. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/mcmcli/logging.py +0 -0
  30. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/setup.cfg +0 -0
  31. {mcm_cli-1.2.0 → mcm_cli-1.3.1}/tests/test_config.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mcm-cli
3
- Version: 1.2.0
3
+ Version: 1.3.1
4
4
  Summary: A command-line interface for Moloco Commerde Media
5
5
  Home-page: https://github.com/moloco-mcm/mcm-cli
6
6
  Author: Moloco MCM Team
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mcm-cli
3
- Version: 1.2.0
3
+ Version: 1.3.1
4
4
  Summary: A command-line interface for Moloco Commerde Media
5
5
  Home-page: https://github.com/moloco-mcm/mcm-cli
6
6
  Author: Moloco MCM Team
@@ -35,7 +35,7 @@ def version():
35
35
  """
36
36
  Show the tool version
37
37
  """
38
- typer.echo(f"Version: mcm-cli v1.2.0")
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
- wa0 = wallet.accounts[0]
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"Wallet ID = {wallet.id}")
77
- print(f"PRE_PAID balance = {money_amount}")
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.2.0',
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