toERP 整體程式架構說明

用圖看懂:它如何運作、由哪些部分組成、各模組現況|2026-10-14

1. 一句話看懂

toERP 是一套 PHP 網頁工具:使用者在網頁填資料,伺服器以 cURL 模擬瀏覽器操作 ERP 網頁,把「人工一筆一筆建檔」變成「批量貼上、自動送出」,並留下完整紀錄。

ERP 沒有提供正式 API,所有對接都來自瀏覽器封包逆向。因此整個專案圍繞三件事設計:像瀏覽器一樣登入與送出、不被 ERP 的 IIS 限流擋下(節流 + 403 重試)、每一步都可追查(trace 與 log)。為了讓新功能容易加入,程式切成「core 共用層」與「各功能模組」兩層,模組只放自己的 ERP 端點、欄位規則與業務流程。

頁面/流程執行動作模組共用core 共用層ERP 外部系統高風險/錯誤

2. 總體框架(由上而下四層)

使用者瀏覽器(HTML + JS)HTTP POST / AJAXtoERP/index.php 功能索引頁(卡片)讀 core/module_registry.php模組層AddOE 新增原廠編號index / S0 / S1 / S2(已完成 V1.7)AddBom 產品主檔 + Z 階 BOMindex / S0 / S1 / S2(僅 CS 類別 MVP)AddUser只有流程文字未實作模組共用addoe_common.php · modules.phpfield_rules.php · config_override.phpaddbom_common.php · modules.phpcomponent_rules.php · field_rules.phpcore 共用層bootstrap.phpsession/設定/引擎page_header.phprender_helpers.php共用頁首與畫面field_rules_common.php欄位驗證三層共用ErpClient v21/v22登入·節流·送出·403debug_writer403 writer(落地 log)ERP(ASP.NET WebForms / IIS)— 無正式 API,以 cURL 模擬瀏覽器操作HTTPS本機檔案debug_logs/ 403/ JSON
層級角色重點
瀏覽器輸入資料、即時檢查、顯示結果每個模組有自己的 JS(驗證、動態新增列、勾選帶入)
模組層各功能的頁面與流程(AddOE、AddBom…)每個模組一個資料夾,頁面按 S0/S1/S2 分檔,各自處理自己的 action
模組共用模組自己的共用函式與設定modules.php 登錄 ERP 端點與 XML 範本;field_rules.php 登錄欄位規則;*_common.php 放共用函式
core 共用層所有模組共用的基礎能力登入、節流、403 重試、XML、驗證、頁首畫面、除錯 log。引擎本身不含任何功能專屬字串
設計取捨:core 保持「模組中立」。例如 AddOE 專屬的「主鍵重複」判斷,在 V22 就從引擎搬到 AddOE 自己的共用檔,避免引擎被單一模組綁死。

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. 一次請求怎麼跑(以批量送出為例)

① 使用者在頁面填資料按「送出」② 瀏覽器端檢查(AddOEValidate.js)③ 頁面 PHP 載入bootstrap → 設定/規則/引擎④ 伺服器端驗證field_check / 筆數上限⑤ 登入 ERPrunLoginWithRetry()⑥ 逐筆送出(節流 1 秒/請求)⑦ 寫 trace / logcleanup + 登出⑧ 畫面列出每筆成功/失敗/略過

實測:AddOE 每筆約 2.0 秒(重開編輯頁與送出各一個請求,各受 1 秒節流),18 筆 36.04 秒、42 筆 85.04 秒。

5. ERP 連線引擎(ErpClient)

login()GET 登入頁→解析隱藏欄位POST 帳密+公司別openEditPage()取得 userno、編輯權限確認 Session 有效迴圈(每筆)重開編輯頁(第2筆起)→ 節流 → buildRowXmlsubmitXml()POST XML 到存檔端點依回應碼判斷結果logout() +cleanup()下一筆任一請求回 HTTP 403→ 拋出 Erp403Exception(帶完整請求上下文)呼叫端寫 403 JSON log登入/第一筆:清除 client、重新登入重試其他筆:中斷該產品代碼、繼續下一個每個請求前 throttle()距上次請求不足 1 秒就補足(避免 IIS 動態 IP 限制回 403)
方法做什麼
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單一產品代碼+ 多行原廠編號S1序號列批量建檔(每列:產品代碼/區域規範/OE)S2查詢 OE → 勾選 → 帶入新增列→ 批量建檔 或 批量刪除共用函式(addoe_common.php)parseMultiLineInput · addoeParseRowsInput · addoeValidateRowsaddoeSubmitMarketnoBatch · addoeRunRowsBatch · 結果表S2 專屬addoeQueryOeByPartno()s2DeleteOneOeFromErp()ERP 端點aodregionplanedit.aspxaaccustnoteitem.aspxERP 端點flowgetlistrexml.aspx(查詢清單)建檔查詢
頁面用途重點規則
S0單一產品代碼 + 多行原廠編號 + 備註每個產品代碼最多 50 筆(可設定)
S1多個產品代碼,每列各自的區域規範與原廠編號最多 10 列;留空列忽略;重複或空原廠編號會擋下;顯示預計時間;單一產品代碼遇 403 時略過並繼續
S2查詢既有 OE(製單/查詢模式、完全/Like 匹配),勾選後帶入新增列,或批量刪除刪除僅限製單模式查得的 OE

S2 批量刪除的五道關卡

① 取回資料state=3(依 planno)② 身分核對4 欄位須與勾選完全一致③ 鎖定getnoXML lock須回 ok④ 刪除state=4editmode=3⑤ 複驗重新查詢確認已不存在任一步失敗就停止該筆並標失敗,其他筆不受影響;只允許「製單」模式查得的 OE 刪除
刪除會真的改動 ERP 資料。正式實測紀錄(成功、鎖定失敗、複驗失敗、403)尚未齊全,「刪除前重新確認目標確實是製單中」也尚未實作,請先用可還原的測試資料使用。

7. AddBom:產品主檔 + Z 階 BOM

S0 查看產品圖片向 ERP 取圖片連結批次處理多個產品編號S1 組件分解(純人工)依圖片在瀏覽器拆解組件保存 bom_componentsS2 組件主檔建立/複製/刪除查複製來源 → 提交 ERP或刪除未審核主檔本機 JSON 資料庫(AddBom 的交接介質){類別}/{類別}-{前2碼}.json 前綴彙整清單{類別}/{完整編號}.json:images · bom_components · ERP 狀態寫入讀/寫讀ERP:產品主檔 view 頁+ abagetremotepic.aspxERP:產品主檔存檔端點+ abaselacnoItem.aspx(查詢是否存在)
階段做什麼資料去向
S0輸入產品編號,向 ERP 取產品圖片連結寫 .url 捷徑、HTML 連結清單、前綴彙整 JSON、單一產品 JSON
S1人工看圖拆解組件(本座、球頭、鐵套、吊架…),瀏覽器即時產生預覽只更新該產品 JSON 的 bom_components,不碰 ERP
S2讀 S1 的組件;向前搜尋 ERP 已存在的編號作「複製來源」(可指定 Z 值);提交建立組件主檔,或刪除未審核主檔寫 ERP;並把各組件的 ERP 狀態回寫本機 JSON

三個階段不共用同一次請求,而是以本機 JSON 檔交接。AddBom 沒有編輯頁設定,所以登入只用「僅登入」流程(runLoginOnlyWithRetry),userno 取自登入帳號小寫。

成熟度:目前只完成 CS 類別產品的 MVP 驗證。下拉選單雖列出 CRE、CSR、CTE、CBH、CSL、CBJ 等類別,但其組件規則與流程尚未實作與驗證。

8. 共通機制

8.1 輸入檢查:三層、規則只寫一次

① 瀏覽器端(即時提示)HTML5 required / patterndata-pattern + JS 逐行比對AddOEValidate.js② 伺服器端(真正把關)parseMultiLineInput 整理field_check / field_check_lines筆數上限 · 重複產品代碼③ ERP 端(最後防線)主鍵重複 → 失敗訊息detectPrimaryKeyViolation()「重複的索引鍵值是 …」規則只定義一次:各模組 field_rules.php(+ core/field_rules_common.php)→ PHP、HTML5、JS 三層自動套用

8.2 設定與規則的合併

core/config.php系統設定模組 config_override.phparray_replace_recursive合併$cfg節流/重試/log 路徑/模組變量core/field_rules_common.php登入欄位規則模組 field_rules.php業務欄位規則array_replace_recursive合併$rulesfield_check() 使用

模組只需覆寫自己要改的鍵。注意:索引陣列依索引合併,覆寫陣列型設定時要提供完整清單。

8.3 403 與節流

ERP 的 IIS 有動態 IP 限制,連續請求容易回 403。對策有三:每個請求間隔至少 1 秒;登入與批次第一筆遇 403 自動重新登入重試;批次中途遇 403 只記錄並略過該產品代碼。403 的完整上下文寫入 403/ JSON log,便於追查。

8.4 除錯與稽核

每次執行都把引擎的動作紀錄(序號、時間、操作說明、回應狀態)與每步驟完整回應存到 debug_logs/,頁面也可勾選顯示追蹤表。效率分析就是直接統計這份紀錄得出的。

9. 如何擴充:新增一個模組

① 建模組目錄例:AddCustNote/② F12 抓真實封包網址/XML/標頭/Cookie③ modules.php端點 + row_template④ field_rules.phpconfig_override.php⑤ index.php 三行MODULE_KEY + bootstrap⑥ module_registry.php加一筆(含 module_dir)

已提出的延伸方向(尚未排程):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 的部分本體,本次僅讀到頁面與函式說明層級,圖中對應描述以頁面程式與文件為準。