#!/usr/bin/env python3 """批量下载 SAP C4C 附件,从 CSV 读取 Ticket ID,并行执行并记录错误日志""" import subprocess import sys import os import json import datetime import csv import glob from concurrent.futures import ThreadPoolExecutor, as_completed import threading # ── 配置 ────────────────────────────────────────────────────────────────────── TENANT = "https://my300375.c4c.saphybriscloud.cn" USER = "admin" PASSWORD = "Xjait.1?" OUTPUT = "./downloads" DSM_URL = "http://10.0.10.235:5000" DSM_USER = "PLM" DSM_PASS = "123456" DSM_PATH = "/Newgonow/AU-SPFJ" WORKERS = 5 SCRIPT = os.path.join(os.path.dirname(__file__), "sap-c4c-AttachmentFolder.py") ERROR_LOG = os.path.join(os.path.dirname(__file__), "error_log.txt") DATASOURCE = os.path.join(os.path.dirname(__file__), "datasource") print_lock = threading.Lock() # ───────────────────────────────────────────────────────────────────────────── def get_ticket_ids(limit=10): ids, seen = [], set() for csv_file in glob.glob(os.path.join(DATASOURCE, "*.csv")): with open(csv_file, encoding="utf-8-sig") as f: reader = csv.reader(f) next(reader, None) for row in reader: if len(row) < 2: continue val = row[1].strip() if val and val not in seen: seen.add(val) ids.append(val) if len(ids) >= limit: break if len(ids) >= limit: break return ids def log_error(ticket_id, message): ts = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") with open(ERROR_LOG, "a", encoding="utf-8") as f: f.write(f"[{ts}] Ticket {ticket_id}: {message}\n") def run_ticket(ticket_id, index, total): with print_lock: print(f"\n[{index}/{total}] 开始下载 Ticket {ticket_id} ...") cmd = [ sys.executable, SCRIPT, "--tenant", TENANT, "--user", USER, "--password", PASSWORD, "--ticket", str(ticket_id), "--output-dir", os.path.join(OUTPUT, str(ticket_id)), "--json", "--dsm-url", DSM_URL, "--dsm-user", DSM_USER, "--dsm-password", DSM_PASS, "--dsm-path", DSM_PATH, ] try: result = subprocess.run(cmd, capture_output=True, text=True, timeout=300) # 解析 JSON 输出 try: data = json.loads(result.stdout) success = data.get("success", False) downloaded = len(data.get("downloadedFiles", [])) dsm_uploads = data.get("dsmUpload", []) ok_uploads = sum(1 for u in dsm_uploads if u.get("success")) fail_uploads = len(dsm_uploads) - ok_uploads if success: with print_lock: print(f" ✓ [{ticket_id}] 下载 {downloaded} 个文件, DSM 上传 {ok_uploads} 成功 {fail_uploads} 失败") if fail_uploads: fails = [u for u in dsm_uploads if not u.get("success")] for u in fails: log_error(ticket_id, f"DSM 上传失败: {u.get('file')} - {u.get('error')}") else: err = data.get("error", result.stderr or "未知错误") with print_lock: print(f" ✗ [{ticket_id}] 失败: {err}") log_error(ticket_id, err) except json.JSONDecodeError: if result.returncode == 0: with print_lock: print(f" ✓ [{ticket_id}] 完成") else: err = result.stderr.strip() or result.stdout.strip() or "未知错误" with print_lock: print(f" ✗ [{ticket_id}] 失败: {err}") log_error(ticket_id, err) except subprocess.TimeoutExpired: msg = "超时 (300s)" with print_lock: print(f" ✗ [{ticket_id}] {msg}") log_error(ticket_id, msg) except Exception as e: with print_lock: print(f" ✗ [{ticket_id}] 异常: {e}") log_error(ticket_id, str(e)) def main(): print("读取 Ticket ID ...") ids = get_ticket_ids(10) if not ids: print("未找到任何 Ticket ID,请检查 datasource 目录") sys.exit(1) print(f"共 {len(ids)} 个 Ticket: {', '.join(ids)}") # 清空/创建 error_log open(ERROR_LOG, "w").close() with ThreadPoolExecutor(max_workers=WORKERS) as executor: futures = {executor.submit(run_ticket, tid, i, len(ids)): tid for i, tid in enumerate(ids, 1)} for future in as_completed(futures): future.result() # 触发异常传播(已在 run_ticket 内处理) print("\n全部完成。") if os.path.getsize(ERROR_LOG) > 0: print(f"有错误,详见 {ERROR_LOG}") else: print("无错误。") if __name__ == "__main__": main()