--- name: tongtool-order-remark description: Log into Tongtool ERP, search for a specific order by ID, and add a remark. --- # Tongtool Order Remark Automation This skill automates the process of logging into the Tongtool ERP system, navigating to a specific order using global search, and adding a custom remark to the order details. ## Dependencies - Python 3 - `DrissionPage` - `ddddocr` - `requests` ## The Script This script performs the following steps: 1. Opens a headless Chromium browser using DrissionPage (Crucial: 1920x1080 window size). 2. Navigates to the Tongtool login page (`passport.tongtool.com`). 3. Uses `ddddocr` to solve the captcha and logs in. 4. Navigates to the ERP dashboard to initialize the session. 5. Uses the global search URL to jump directly to the target order's detail page. 6. Clicks the "Add Remark" button (`#addOrderRemark`). 7. robustly injects the desired remark into the text area using JS events. 8. Clicks the "Save" button to apply the remark using `by_js=True`. ```python from DrissionPage import ChromiumPage, ChromiumOptions import ddddocr, requests, json, time, os def add_order_remark(order_id: str, note_text: str, user: str = 'ozonezsjgw@163.com', pwd: str = '111111'): co = ChromiumOptions() # Path to playwright Chromium 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') # CRITICAL: Use a large window size to ensure the responsive UI displays the detail pane and action buttons co.set_argument('--window-size=1920,1080') co.headless() co.auto_port() driver = ChromiumPage(co) # Helper: Fix ddddocr misrecognitions def correct_ocr(raw_code): cleaned = ''.join(c for c in raw_code if c.isascii() and c.isalnum()) return cleaned.translate(str.maketrans('oliOSsZz', '01105522')) # Helper: Close layui popups that block interaction def nuke_popups(page): try: page.run_js(""" document.querySelectorAll('.layui-layer-shade, .layui-layer, .modal, .overlay, .jclose-blue, .close, [title="关闭"], .layui-layer-close').forEach(el => { try { el.remove(); } catch(e){} }); """) except: pass # Login function with retry mechanism 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) img = driver.ele('css:img.pic-yzm') if not img: time.sleep(2) continue src = img.attr('src') cookies = {c['name']: c['value'] for c in driver.cookies()} try: resp = requests.get(src, cookies=cookies, timeout=10) raw = ddddocr.DdddOcr(show_ad=False).classification(resp.content) code = correct_ocr(raw) if len(code) < 4: continue driver.ele('css:input[name="captcha"]').input(code) driver.ele('css:button.btn-primary').click() time.sleep(5) except Exception as e: print(f"Login request failed: {e}") continue for _ in range(5): if 'member' in driver.url or 'dashboard' in driver.url or 'yijiety' in driver.url: return True time.sleep(2) if 'passport' in driver.url: body = driver.ele('tag:body').text if '验证码输入错误' in body: continue # Retry loop elif '密码' in body and '错误' in body: print("Wrong password") return False return False print("Attempting login...") success = login(driver, user, pwd) if not success: print("Login failed after max retries.") driver.quit() return False print("Login successful.") # Enter ERP to set session completely driver.get("https://yijiety.tongtool.com/dashboard/homepage/index.htm") time.sleep(8) nuke_popups(driver) # Navigate to the specific order using global search print(f"Navigating to order: {order_id}") search_url = ( f"https://yijiety.tongtool.com/search/order.htm" f"?search_text_value={order_id}" f"&search_mark=salesRecordNumber" f"&source=global" ) driver.get(search_url) time.sleep(12) nuke_popups(driver) # Attempt to add the remark remark_added = False btn = driver.ele('css:#addOrderRemark') if btn: a_tag = btn.ele('tag:a') if a_tag: a_tag.click(by_js=True) time.sleep(3) textarea = driver.ele('tag:textarea') if textarea: print("Writing remark robustly...") # MUST use JS dispatch for layui to detect the model change js = f""" var ta = document.querySelector('textarea'); if(ta) {{ ta.value = '{note_text}'; ta.dispatchEvent(new Event('input', {{bubbles: true}})); ta.dispatchEvent(new Event('change', {{bubbles: true}})); }} """ driver.run_js(js) time.sleep(1) for a in driver.eles('tag:a'): if a.text.strip() == '保存': a.click(by_js=True) time.sleep(3) print("Remark saved successfully!") remark_added = True break else: print("Could not find the text area for the remark.") else: print("Could not find clickable element inside the remark button.") else: print("Could not find the remark button (#addOrderRemark) on the page.") driver.quit() return remark_added if __name__ == '__main__': # Usage Example: order_id = "16Ezyhbg-PO-211-05103794125430842" custom_note = "Testing Order Remark Automation" add_order_remark(order_id, custom_note) ``` ## Pitfalls * **Window Size Requirement (CRITICAL):** It is critical to set a large window size (e.g., `--window-size=1920,1080`). The global search page uses a responsive grid. Without a wide window, the details pane (containing the remark button and other actions) may not be exposed or rendered in the DOM natively. * **JS Event Dispatching for Textareas (CRITICAL):** Using `textarea.input('text')` often fails to update the underlying layui/Vue model, resulting in a blank note being saved. Always use `driver.run_js` to set `value` and dispatch `input` and `change` events natively. * **JS Click for Save:** The save dialog anchor should be clicked with `by_js=True` (`a.click(by_js=True)`) because overlapping layui shades often block standard WebDriver clicks. * **CSS Selector for Remark Button:** The button has a specific ID. You must use `driver.ele('css:#addOrderRemark')`, and then click the `` tag nested inside it. * **Popups Blocking Interaction:** Tongtool frequently shows `layui` popups (announcements) that cover the screen. Ensure the aggressive `nuke_popups` function is called before interacting.