-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcli.py
More file actions
124 lines (100 loc) · 5.01 KB
/
Copy pathcli.py
File metadata and controls
124 lines (100 loc) · 5.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
"""CLI do bitrix24-python-sdk.
Uso:
python cli.py deals list [--stage NEW] [--limit 20]
python cli.py leads export --csv saida.csv
python cli.py call crm.deal.fields
python cli.py call crm.deal.list --params "{\"filter\": {\"STAGE_ID\": \"WON\"}}"
Conexão:
* defina B24_WEBHOOK_URL no ambiente (ou num arquivo .env na raiz), OU
* use --webhook https://portal.bitrix24.com.br/rest/1/token, OU
* não defina nada e o CLI roda em MODO MOCK (portal fake em memória).
"""
import argparse
import csv
import json
import os
import sys
from bitrix24 import CRM, Bitrix24Client, create_mock_client, fetch_all
def _load_dotenv(path=".env"):
"""Leitor minimalista de .env (KEY=VALUE, sem dependências)."""
values = {}
if os.path.exists(path):
with open(path, encoding="utf-8") as handle:
for line in handle:
line = line.strip()
if line and not line.startswith("#") and "=" in line:
key, _, value = line.partition("=")
values[key.strip()] = value.strip().strip('"').strip("'")
return values
def _build_client(args):
url = args.webhook or os.environ.get("B24_WEBHOOK_URL") or _load_dotenv().get("B24_WEBHOOK_URL")
if args.mock or not url:
if not args.mock:
print("[aviso] B24_WEBHOOK_URL não definido — rodando em MODO MOCK "
"(portal fake em memória).\n", file=sys.stderr)
return create_mock_client()
return Bitrix24Client(url)
def cmd_deals_list(args):
client = _build_client(args)
filtro = {"STAGE_ID": args.stage} if args.stage else None
deals = fetch_all(client, "crm.deal.list", {"filter": filtro} if filtro else None)
print(f"{'ID':>6} {'ESTÁGIO':<20} {'VALOR':>14} TÍTULO")
print("-" * 90)
for deal in deals[: args.limit]:
valor = f"R$ {float(deal.get('OPPORTUNITY') or 0):,.2f}"
print(f"{deal['ID']:>6} {deal.get('STAGE_ID', ''):<20} {valor:>14} {deal.get('TITLE', '')}")
if len(deals) > args.limit:
print(f"... e mais {len(deals) - args.limit} negócio(s).")
print(f"\nTotal: {len(deals)} negócio(s)" + (f" no estágio {args.stage}" if args.stage else ""))
return 0
def cmd_leads_export(args):
client = _build_client(args)
leads = fetch_all(client, "crm.lead.list")
colunas = ["ID", "TITLE", "NAME", "LAST_NAME", "STATUS_ID", "SOURCE_ID",
"OPPORTUNITY", "CURRENCY_ID", "PHONE", "EMAIL", "DATE_CREATE"]
with open(args.csv, "w", newline="", encoding="utf-8-sig") as handle:
writer = csv.DictWriter(handle, fieldnames=colunas, extrasaction="ignore", delimiter=";")
writer.writeheader()
for lead in leads:
row = dict(lead)
# multifields (PHONE/EMAIL) viram o primeiro valor, legível no Excel
for multi in ("PHONE", "EMAIL"):
valores = row.get(multi)
row[multi] = valores[0]["VALUE"] if isinstance(valores, list) and valores else ""
writer.writerow(row)
print(f"{len(leads)} lead(s) exportado(s) para {args.csv}")
return 0
def cmd_call(args):
client = _build_client(args)
params = json.loads(args.params) if args.params else None
payload = client.call(args.method, params)
print(json.dumps(payload.get("result"), indent=2, ensure_ascii=False, default=str))
if "total" in payload:
print(f"\ntotal: {payload['total']}", file=sys.stderr)
return 0
def main(argv=None):
parser = argparse.ArgumentParser(
prog="cli.py", description="CLI do SDK Python para a API REST do Bitrix24."
)
parser.add_argument("--webhook", help="URL do webhook de entrada (sobrepõe B24_WEBHOOK_URL)")
parser.add_argument("--mock", action="store_true", help="força o modo mock (portal fake)")
sub = parser.add_subparsers(dest="comando", required=True)
p_deals = sub.add_parser("deals", help="operações com negócios")
sub_deals = p_deals.add_subparsers(dest="acao", required=True)
p_deals_list = sub_deals.add_parser("list", help="lista negócios (todas as páginas)")
p_deals_list.add_argument("--stage", help="filtra por STAGE_ID (ex.: NEW, WON)")
p_deals_list.add_argument("--limit", type=int, default=20, help="máx. de linhas exibidas")
p_deals_list.set_defaults(func=cmd_deals_list)
p_leads = sub.add_parser("leads", help="operações com leads")
sub_leads = p_leads.add_subparsers(dest="acao", required=True)
p_leads_export = sub_leads.add_parser("export", help="exporta todos os leads para CSV")
p_leads_export.add_argument("--csv", required=True, help="arquivo de saída (ex.: saida.csv)")
p_leads_export.set_defaults(func=cmd_leads_export)
p_call = sub.add_parser("call", help="chama qualquer método REST cru")
p_call.add_argument("method", help="ex.: crm.deal.fields")
p_call.add_argument("--params", help='JSON com os parâmetros (ex.: \'{"id": 42}\')')
p_call.set_defaults(func=cmd_call)
args = parser.parse_args(argv)
return args.func(args)
if __name__ == "__main__":
sys.exit(main())