--- name: tongtool-erp-automation description: Automate Tongtool (通途) ERP using DrissionPage — login, CAPTCHA solving, tab switching, iframe navigation, and popup handling. --- # Tongtool ERP Automation Use this skill when the user asks to log in, navigate, or extract data from the Tongtool ERP system (`tongtool.com`). ## Setup Ensure `DrissionPage` and `ddddocr` are installed. ```python from DrissionPage import ChromiumPage, ChromiumOptions import ddddocr, os, shutil, time co = ChromiumOptions() co.set_browser_path('/home/ubuntu/.cache/ms-playwright/chromium-1217/chrome-linux64/chrome') co.set_argument('--no-sandbox') co.set_argument('--disable-dev-shm-usage') co.headless() co.auto_port() driver = ChromiumPage(co) ``` ## 1. Login — Two Methods ### 1a. Headless DrissionPage Login + CAPTCHA (Server-side) Target: `https://passport.tongtool.com/` Credentials are usually `ozonezsjgw@163.com` / `111111`. ```python import re, requests def correct_ocr(raw_code): """Fix common ddddocr misreads for Tongtool captcha.""" return raw_code.translate(str.maketrans('oliOSsZz', '01105522')) def login(driver, user, pwd, max_retry=5): for attempt in range(max_retry): driver.get('https://passport.tongtool.com/') time.sleep(3) driver.ele('css:input[name="username"]').input(user) driver.ele('css:input[name="password"]').input(pwd) # CAPTCHA: selector is img.pic-yzm img = driver.ele('css:img.pic-yzm') src = img.attr('src') cookies = {c['name']: c['value'] for c in driver.cookies()} resp = requests.get(src, cookies=cookies, timeout=10) raw = ddddocr.DdddOcr(show_ad=False).classification(resp.content) code = correct_ocr(raw) driver.ele('css:input[name="captcha"]').input(code) driver.ele('css:button.btn-primary').click() time.sleep(6) # Wait for redirect from /check to /member for _ in range(5): if 'member' in driver.url: return True time.sleep(2) # Check if still on login page if 'passport' in driver.url: body = driver.ele('tag:body').text if '验证码输入错误' in body: continue # retry elif '密码' in body and '错误' in body: raise ValueError('Wrong password') return False ``` **Key points**: - Captcha image selector: `img.pic-yzm` (not `@src^=/api/common/code`). - Login button: `button.btn-primary` (not `text:立即登录`). - After submit, URL lands on `/check` then redirects to `member.tongtool.com` — wait for `member` in URL. - `correct_ocr()` fixes common ddddocr misreads (o→0, l→1, O→0, S→5, s→5, Z→2, z→2). ### 1b. CDP-Based Login via Bridge (Alternative — Desktop-side) Use this when headless login is blocked by device verification or captcha. The Desktop Chrome is already a trusted device, so no captcha or device approval is needed. **Prerequisites**: A Desktop slot connected to Bridge with CDP enabled. Trigger `/cdp/snapshot` first to establish CDP session. **Key CDP evaluate response structure**: `r['result']['result']['value']` — Bridge returns `{ok: true, result: {result: {type: "...", value: ...}}}`. **Flow**: 1. Navigate: `POST /cdp/navigate` -> `https://passport.tongtool.com/` 2. Fill username via native setter: `Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set.call(inp, 'ozonezsjgw@163.com')` 3. Fill password via native setter 4. Click login button by text `立即登录` 5. Wait for redirect: `member.tongtool.com` 6. Navigate to ERP: `https://yijiety.tongtool.com/dashboard/homepage/index.htm` **Full Python helper**: ```python def evaluate(js, slot='desktop-mq27qgb0'): r = bridge_post('/cdp/evaluate', {'slot': slot, 'expression': js}) if r.get('ok') and r.get('result') and r['result'].get('result'): return r['result']['result'].get('value') return r ``` ## 2. Enter ERP After successful login (`member.tongtool.com`), the simplest and most reliable way to enter the ERP is **direct navigation** — no tab switching needed. ```python # Method 1 (Recommended): Direct navigation driver.get("https://yijiety.tongtool.com/dashboard/homepage/index.htm") time.sleep(8) # SPA takes time to bootstrap # Verify by checking body text body = driver.ele('tag:body').text if '发货管理' in body: print("✅ ERP loaded") else: print("❌ ERP not loaded") ``` **Deprecated**: The old "click 进入系统 then switch tab" approach is flaky in headless mode. Direct navigation is faster and more stable because session cookies are already set. ## 3. TEMU Semi-Managed Order — Bulk Shipping Info & Remark ### Complete workflow: login → wait stock page → filter TEMU → read shipping → add remark **Typical scenario**: The user wants to find the cheapest shipping method for TEMU semi-managed orders in "等待配货" status and record it in each order's remark. **Critical finding**: For TEMU semi-managed orders in **等待配货** status, the system has **already auto-calculated and assigned the cheapest shipping method** (e.g., 湖北众信 EJET-SpeedX). There is NO need to trigger an explicit "运费试算" — the logistics provider, tracking method, and price are already visible in the order detail panel once you click the order row. ### 3.1 Navigate to Wait Stock page ```python driver.get("https://yijiety.tongtool.com/warehouse/assignStockSelfMaintenance/index.htm") time.sleep(10) ``` ### 3.2 Set warehouse via hidden input (custom `t_combo_box`) The warehouse dropdown is a **custom `t_combo_box` component** that cannot be triggered by standard clicks. The reliable method is: ```python def set_warehouse(driver, warehouse_name): """Set warehouse by manipulating hidden input + clicking the TD cell.""" # Option A: use the hidden input directly js = f""" var hidden = document.querySelector('input[name="warehouseSelect"]'); if (hidden) {{ hidden.value = '{warehouse_name}'; var event = new Event('change', {{ bubbles: true }}); hidden.dispatchEvent(event); return 'set via hidden input'; }} return 'hidden input not found'; """ result = driver.run_js(js) time.sleep(2) # Option B: click the TD that contains the warehouse text js2 = f""" var tds = document.querySelectorAll('td'); for (var i=0; i