1. 一句話看懂
ERP 沒有提供正式 API,所有對接都來自瀏覽器封包逆向。因此整個專案圍繞三件事設計:像瀏覽器一樣登入與送出、不被 ERP 的 IIS 限流擋下(節流 + 403 重試)、每一步都可追查(trace 與 log)。為了讓新功能容易加入,程式切成「core 共用層」與「各功能模組」兩層,模組只放自己的 ERP 端點、欄位規則與業務流程。
2. 總體框架(由上而下四層)
| 層級 | 角色 | 重點 |
|---|---|---|
| 瀏覽器 | 輸入資料、即時檢查、顯示結果 | 每個模組有自己的 JS(驗證、動態新增列、勾選帶入) |
| 模組層 | 各功能的頁面與流程(AddOE、AddBom…) | 每個模組一個資料夾,頁面按 S0/S1/S2 分檔,各自處理自己的 action |
| 模組共用 | 模組自己的共用函式與設定 | modules.php 登錄 ERP 端點與 XML 範本;field_rules.php 登錄欄位規則;*_common.php 放共用函式 |
| core 共用層 | 所有模組共用的基礎能力 | 登入、節流、403 重試、XML、驗證、頁首畫面、除錯 log。引擎本身不含任何功能專屬字串 |
3. 目錄結構
toERP/ ├── index.php 功能索引頁(卡片式 3x4 = 12 格,讀 module_registry.php) ├── core/ 共用層(所有模組共用) │ ├── bootstrap.php 模組初始化:session 隔離、設定/規則合併、引擎選擇、登入重試 │ ├── module_registry.php 模組清單(索引頁與 bootstrap 都讀這份) │ ├── config.php 系統設定(節流、重試、編碼、log 路徑) │ ├── field_rules_common.php 欄位驗證函式 + 共用登入欄位規則 │ ├── ErpClient_v21.php / ErpClient_v22.php ERP 連線引擎(v22 另有 fetchRaw) │ ├── ComponentXmlOperations.php XML 解析(含多列解析) │ ├── page_header.php / render_helpers.php / acc.php 共用頁首與畫面元件 │ ├── debug_set.php / debug_writer.php / error403_writer.php / erp_header_diag.php 除錯與 log │ └── js/ComponentBomRenderer.js BOM 表格共用渲染(S1/S2 共用) ├── AddOE/ 新增原廠編號 │ ├── index.php S0.php S1.php S2.php (OE-DEL.php 測試用診斷工具) │ ├── addoe_common.php modules.php field_rules.php config_override.php lookup_part.php │ └── js/AddOEValidate.js AddOES1.js AddOES2.js ├── AddBom/ 產品主檔 + Z 階 BOM │ ├── index.php S0.php S1.php S2.php │ ├── addbom_common.php modules.php component_rules.php field_rules.php config_override.php │ └── js/AddBomShared.js AddBomValidate.js AddBom.js AddBomS1.js AddBomS2.js ├── AddUser/ 只有 AddUser-ERP-workflow.txt(無 PHP) └── Doc/ 全部開發文件
執行時產生的檔案
debug_logs/yyyymmdd-hhmm/ 每次執行的動作紀錄表 + 每步驟完整回應檔
403/yyyy-mm-dd/ 403 的 JSON log(步驟、URL、標頭、回應片段)
/tmp/erp_cookie_{模組}_{session}.txt 登入 Cookie 暫存(結束時刪除)
AddBom: url/ 與 {類別}/*.json S0~S2 之間交接的本機資料
debug_logs/ 與 403/ 內含 Cookie 與完整頁面內容,需用 Nginx 規則擋掉外部存取,或放在網站根目錄外。
4. 一次請求怎麼跑(以批量送出為例)
- ②③ 先擋後載:瀏覽器端先檢查格式,不合就不送出;送出後 PHP 頁面第一行載入
bootstrap.php,依模組代號(MODULE_KEY)隔離 session、合併設定與規則、選擇引擎版本。 - ④ 伺服器端才是真正把關:不依賴瀏覽器,再驗一次帳密格式、筆數上限、重複產品代碼、欄位格式。
- ⑤⑥ 登入與送出:登入失敗或遇到 403 會自動重試;送出時每個請求之間至少間隔 1 秒。
- ⑦ 一定留下紀錄:不論成功失敗,最後都寫入 trace、清理 Cookie 並登出。
實測:AddOE 每筆約 2.0 秒(重開編輯頁與送出各一個請求,各受 1 秒節流),18 筆 36.04 秒、42 筆 85.04 秒。
5. ERP 連線引擎(ErpClient)
| 方法 | 做什麼 |
|---|---|
login() / openEditPage() | 登入並開啟編輯頁,取得 userno 與編輯權限,確認登入生效 |
buildRowXml() / submitXml() | 依模組的 row_template 組出 XML,帶 Referer/Origin 標頭送到存檔端點 |
fetchRaw()(v22) | 對任意網址發 GET/POST 並取回原始內容;AddOE 的查詢與刪除、AddBom 的查圖與查複製來源都靠它 |
throttle() / guardHttpStatus() | 節流;遇 HTTP 403 拋出攜帶完整請求上下文的例外,供寫 log 與重試 |
getTraceLog() / cleanup() | 取出動作紀錄;登出、關閉連線、刪除 Cookie 檔 |
編碼由設定決定(erp_charset),引擎在送出與接收時轉換;fetchRaw() 回傳原始位元組,HTML 內容需呼叫端自行轉碼。
6. AddOE:新增原廠編號(OE)
| 頁面 | 用途 | 重點規則 |
|---|---|---|
| S0 | 單一產品代碼 + 多行原廠編號 + 備註 | 每個產品代碼最多 50 筆(可設定) |
| S1 | 多個產品代碼,每列各自的區域規範與原廠編號 | 最多 10 列;留空列忽略;重複或空原廠編號會擋下;顯示預計時間;單一產品代碼遇 403 時略過並繼續 |
| S2 | 查詢既有 OE(製單/查詢模式、完全/Like 匹配),勾選後帶入新增列,或批量刪除 | 刪除僅限製單模式查得的 OE |
S2 批量刪除的五道關卡
7. AddBom:產品主檔 + Z 階 BOM
| 階段 | 做什麼 | 資料去向 |
|---|---|---|
| S0 | 輸入產品編號,向 ERP 取產品圖片連結 | 寫 .url 捷徑、HTML 連結清單、前綴彙整 JSON、單一產品 JSON |
| S1 | 人工看圖拆解組件(本座、球頭、鐵套、吊架…),瀏覽器即時產生預覽 | 只更新該產品 JSON 的 bom_components,不碰 ERP |
| S2 | 讀 S1 的組件;向前搜尋 ERP 已存在的編號作「複製來源」(可指定 Z 值);提交建立組件主檔,或刪除未審核主檔 | 寫 ERP;並把各組件的 ERP 狀態回寫本機 JSON |
三個階段不共用同一次請求,而是以本機 JSON 檔交接。AddBom 沒有編輯頁設定,所以登入只用「僅登入」流程(runLoginOnlyWithRetry),userno 取自登入帳號小寫。
8. 共通機制
8.1 輸入檢查:三層、規則只寫一次
8.2 設定與規則的合併
模組只需覆寫自己要改的鍵。注意:索引陣列依索引合併,覆寫陣列型設定時要提供完整清單。
8.3 403 與節流
ERP 的 IIS 有動態 IP 限制,連續請求容易回 403。對策有三:每個請求間隔至少 1 秒;登入與批次第一筆遇 403 自動重新登入重試;批次中途遇 403 只記錄並略過該產品代碼。403 的完整上下文寫入 403/ JSON log,便於追查。
8.4 除錯與稽核
每次執行都把引擎的動作紀錄(序號、時間、操作說明、回應狀態)與每步驟完整回應存到 debug_logs/,頁面也可勾選顯示追蹤表。效率分析就是直接統計這份紀錄得出的。
9. 如何擴充:新增一個模組
- core 層完全不用改:登入、節流、403 重試、除錯、頁首、驗證都直接共用。
- 最關鍵的是第 ②③ 步:新功能一律先抓真實封包,不要假設 XML 格式與既有模組相同。
module_registry.php的module_dir一定要填,bootstrap 靠它找到模組目錄。索引頁共 12 格,目前用了 2 格。- 先用可刪除的測試資料小量測試,確認 trace 與 403 log 正常寫入,再正式使用。
已提出的延伸方向(尚未排程):CSV/Excel 匯入、AddBom 擴充其他類別、AddUser、刪除前預覽與 CSRF、結果匯出、效率統計、API/排程化。
10. 目前現況一覽
| 項目 | 狀態 | 說明 |
|---|---|---|
| core 共用層 | 可用 | 引擎 v21/v22、bootstrap、頁首、驗證、除錯 log |
| AddOE S0/S1/S2 | 可用 | 建立與查詢已實測;批量刪除已實作但正式實測紀錄未齊 |
| AddBom S0/S1/S2 | 僅 CS 類別 MVP | 其他類別未實作 |
| AddUser | 未實作 | 只有流程文字說明;registry 中為註解狀態 |
| 安全防護 | 未做 | CSRF 保護、S2 刪除前預覽(dry-run)尚未實作 |
本文依專案庫說明文件與目前 PHP/JS 程式整理。AddBom 的各支 JS 與 addbom_common.php 內部函式、AddOE/addoe_common.php 的部分本體,本次僅讀到頁面與函式說明層級,圖中對應描述以頁面程式與文件為準。