前十七章談的是怎麼把法規知識工作自動化。本章談一件同樣工程化、卻很少被寫進技術白皮書的事:怎麼把它變成可販售、可退費、可派工的單位。這一層的錯誤不會產生錯誤的毒理結論,但會直接產生錯誤的金額——而金額的錯誤沒有 fail-safe 方向可言。
org_is_paid 判定不看「曾經付過錢」,而看目前是否還有點數。點數歸零即回到試用限制,再購即恢復。舊的「曾有成功訂單即永久付費」條款會讓 0 點用戶永久保留付費功能,已移除。PIF 建檔是一種事件驅動的需求:一個品牌商可能一年上架三支新品,然後半年沒有動作。對這樣的使用型態,月租席次制會讓客戶為「沒在用的月份」付費,而這正是中小品牌對合規工具最大的抗拒點。
因此計價的最小單位是產出:一份安全評估報告 = 一點。方案(Pro / Enterprise)仍存在,但它賣的是額度捆綁與週邊能力(產品位、PDF 匯出、無限毒理查詢),而非存取權本身。
這個決策的工程後果是:付費與否不是一個布林欄位,而是一個需要即時計算的狀態。
app/services/feature_access.py 的 org_is_paid() 依序檢查四個條件,任一成立即為付費:
plan_exempt)——合作夥伴與內部帳號billing_exempt)pro / enterprise第 4 條取代了早期的「曾有付款成功訂單 → 永久付費」。舊條款的問題很具體:一個買了單份報告、用完歸零的用戶,會永久保留 AI 配方解析等付費功能——平台持續為他支付 AI 視覺辨識成本,而他不再付費。改為看當前餘額後,點數歸零即回到試用限制,再購即恢復。
點數餘額決定功能權限,但不決定產品位上限。產品位改以 lifetime_purchased(終身累計購買報告數)授予,不隨消耗縮減。
理由是資料可及性:若產品位也跟著餘額走,一個客戶用完點數後,他已經建好的產品會超出上限而被鎖住——那等於用計費機制扣押客戶自己的合規資料。功能可以收回,已交付的資料不行。
報告點數以包售出(份數越多、單價越低)。這產生一個明顯的套利路徑:買最大包拿到最低單價 → 只用幾份 → 申請退剩餘 → 等於以大包單價買了零售量。
app/services/refund_calc.py 的規則消除它:
退款 = 已付金額 − 已用份數 × 「已用份數所對應階梯的單價」
關鍵在第二項用的不是購買時的單價,而是實際用量對應的階梯單價。買 50 份只用 3 份,那 3 份就按 3 份的零售單價計。用量歸屬採 FIFO。
這個模組刻意寫成純函式、無 DB、無外呼——退款金額是最不該有隱藏狀態的計算。實際的退刷、折讓、扣點、標記訂單由 payments 端依本模組算出的金額執行。
平台能自動化的是知識工作。但 PIF 流程中有兩類工作本質上不能被自動化:
| 類型 | 為什麼不能自動化 | 委外對象 |
|---|---|---|
| SA 簽署 | 法規要求具資格的自然人簽名負責 | 合作安全評估師 |
| 實驗室檢測 | 物理上必須等待(安定性、微生物、重金屬) | 合作檢驗機構 |
service_vendors / service_orders / service_admin 三個模組構成這一層:租戶下單 → 平台派工給供應商 → 進度回報 → 月結拆帳。系統同時記錄進價與售價,因為這是平台與供應商之間的實際對帳基礎。
一個設計約束值得記錄:SA 簽署必須綁定一份具體報告——平台產出的或客戶自備的都可以,但不能是「泛泛地簽這個產品」。SA 簽的是那一份報告的那一版內容,這與第 13 章的簽章 metadata(內容雜湊 + 版本綁定)是同一個原則的延續。
委外服務有平台級總開關,預設關閉。理由在程式碼註解中寫明:確認可履約之後,才在供應商與服務價格頁打開。對外宣傳一個買了卻無法履約的服務,比不提供它更糟。
refund_calc 的階梯是保底表,與 DEFAULT_PACKAGES 對齊;若行銷端調整包裝而未同步階梯,會算出偏離的退款額。這是一個尚未被測試鎖住的雙來源風險。payment_settings.packages 提供且可被後台覆寫;曾發生過「頁面寫舊價、資料庫已調新價」的不實陳述,因此定價一律動態呈現。計費層的工程原則與本書其他章節不同——這裡沒有 fail-safe 方向。毒理判定可以「寧偽陽不偽陰」,金額不行:多收與少收都是錯的。因此這一層的設計偏好是純函式、可單元測試、單一來源,把不確定性擋在計算之外。
| 版本 | 日期 | 摘要 |
|---|---|---|
| v0.4 | 2026-08-24 | 首次撰寫。涵蓋報告點數制設計理由、付費身分跟著餘額走(取代永久付費條款)、產品位棘輪制的不對稱、防套利階梯退費、委外履約層與 SA 綁報告約束。 |
© 2026 Baiyuan Tech. Licensed under CC BY-NC 4.0.