REGULAR ORDER PAYMENT API

定期購到了建單時間,mweb 如何完成這一期訂單?

排程送來定期購資料後,mweb 會先確認這次請求是否已完成,再組出可供結帳的資料。接著依付款方式執行建單流程,並記錄本次結果。

01
從 API 入口到建單結果
定期購自動建單的主要分支流程 排程呼叫 mweb API。已成功的 TraceId 直接回傳既有結果;其他請求建立虛擬購物車,Provider 不一致時停止。一致時建立付款 Context,依信用卡或貨到付款流程建單,成功後更新 Tracing。 已成功其餘請求不一致一致信用卡貨到付款 定期購排程或 Worker送出本期建單資料 SubscriptionOrderAutoGen檢查來源、重複請求與 Tracing Tracing 已成功? 回傳既有結果不再執行建單 建立定期購用的虛擬購物車執行 GetRegularOrder Processor Pipeline Provider 相符? 拋出例外不進入付款與建單 建立 PayProcessContext執行 GetPayProcess 並補收件人、發票資料 付款方式? CreditCardProcess建立訂單並執行信用卡授權流程 CashOnDeliveryProcess建立貨到付款訂單 建單成功後更新 Tracing記錄正式訂單識別資訊並回傳
定期購排程或 Worker送出本期建單資料
SubscriptionOrderAutoGen檢查來源、重複請求與 Tracing
Tracing 已成功?
是,回傳既有結果不再執行建單
否,繼續處理建立虛擬購物車
以下沿「繼續處理」分支
虛擬購物車執行 GetRegularOrder Pipeline
Provider 相符?
否,拋出例外不進入付款與建單
是,繼續處理建立付款 Context
以下沿「繼續處理」分支
PayProcessContext執行 GetPayProcess,補收件人與發票資料
付款方式?
CreditCardProcess建單與信用卡授權流程
CashOnDeliveryProcess建立貨到付款訂單
建單成功後更新 Tracing記錄正式訂單識別資訊並回傳
箭頭依執行順序閱讀。圖中付款分支聚焦信用卡與貨到付款;其他付款方式由各自的 PayProcessFlowType 處理。
Provider 檢查範圍:圖中的比對描述 GameBall 與 Nine1V2。程式內的舊 Nine1 分支不執行這項比對。
02
虛擬購物車沿著哪些處理階段形成?

ShoppingCartV2Service.GetShoppingCartContextForRegularOrder() 先放入請求資料與商店設定,再執行 GetRegularOrder Pipeline。軌道由上往下呈現主要處理階段。

輸入:定期購請求、商店 Provider、商品與配送資料
1
取出定期購資料
驗證會員與 Provider,整理商品節點及贈品。
GetRegularOrderProcessorRegularOrderGiftPrepareProcessor
2
檢查可用條件
確認交期、付款方式與配送方式。
GetPayTypeIsAvaliableProcessorCheckShippingProfileTypeIsAvaliableV2Processor
3
計算金物流
算出金物流交集、運費、金額限制與可用組合。
CalculateShoppingCartPayShippingV2ProcessorCalculateShoppingCartFeeV2Processor
4
選定結帳資料
預選結帳方式,計算配送日期與供應商物流代碼。
PickupShoppingCartCheckoutTypeV2ProcessorCalculateShoppingCartShippingDateV2Processor
輸出:ShoppingCartClientEntity,交給付款 Context 建立流程
圖依 GetRegularOrder 的註冊順序分組,列出代表性 Processor。其餘檢查與設定仍在同一條 Pipeline 中;context.IsFinish 成立時會提前停止。
03
付款 Context 在哪些元件之間完成?

TradesOrderService 將虛擬購物車交給 PayProcessService。時序圖把 Context 建立、暫存、GetPayProcess Pipeline,以及外層補資料分開呈現。

PayProcessContext 建立時序圖 TradesOrderService 呼叫 PayProcessService 建立付款 Context。PayProcessService 檢查購物車、建立並暫存 Context,執行 GetPayProcess Pipeline。回傳後,TradesOrderService 補定期購收件人及發票資料。 TradesOrderService PayProcessService UserDataHelper GetPayProcessPipeline 建立定期購付款 Context 檢查購物車非空建立 Context 與識別碼 Save(Context) ExecuteProcess("GetPayProcess") 依序執行 Processor付款資料與 Token配送與門市檢查驗證與個資遮罩 Pipeline 結束,回傳 Context回傳付款 Context 外層補定期購資料收件人、My 發票與可選的會員發票欄位
時間由上往下。GetPayProcess 的 Processor 依序處理付款資料、Token、配送、驗證與遮罩;收件人及發票的定期購專用補值發生在 Pipeline 回傳後。
04
實際付款與建單如何分流?

PayProcessService.CreateTradesOrder() 依 PayProcessFlowType 選擇 Processor Pipeline。雙泳道以相同階段對照信用卡與貨到付款,節點沿各自的垂直線往下執行。

CreateTradesOrder() → ExecuteProcess(PayProcessFlowType)
CreditCardProcess信用卡
檢查信用卡格式、黑名單、分期與付款資料CheckCreditCardProcessor
計算與組單購物車計價、贈品處理、映射與驗證訂單資料MapToTradesOrderProcessor
建立訂單寫入訂單,接著處理 Event、活動名額與其他權益CreateTradesOrderProcessor
信用卡授權3D 驗證節點後執行授權,再進入定期購與訂單後續處理ThreeDSecureProcessor → AuthProcessor
CashOnDeliveryProcess貨到付款
檢查整理並驗證付款資料與配送條件ValidateProcessDataProcessor
計算與組單購物車計價、贈品處理、映射與驗證訂單資料MapToTradesOrderProcessor
建立訂單寫入訂單,接著處理 Event、活動名額與其他權益CreateTradesOrderProcessor
轉單與後續處理轉單到 ERP,接著執行定期購與訂單後續處理TransferOrderProcessor
泳道由上往下表示註冊順序,列出代表性 Processor。信用卡在 CreateTradesOrderProcessor 之後才到 ThreeDSecureProcessor 與 AuthProcessor;貨到付款沒有這兩個信用卡授權節點。context.IsFinish 成立時,後續 Processor 不再執行。
PROVIDER GATE · 定期購責任來源

Provider 檢查是做什麼的?

mweb 會確認「商店目前設定的定期購 Provider」與「這次 API 請求宣告的 Provider」一致。兩者不同時,這次請求不能繼續把定期購資料組成付款用的購物車。

01兩個 Provider 從哪裡來?

商店設定代表目前由哪套定期購流程負責;請求值代表這次呼叫宣告的來源。mweb 建立購物車 context 時,分別把它們放進以下欄位。

商店目前的設定context.Data.RegularOrderProvider由 GetShopDefaultValue 讀取 RegularOrder / RegularOrderProvider
這次 API 請求context.RegularOrderData.Data.Provider來自 request 的 RegularOrderProvider
兩個 Provider 是否相同?GetRegularOrderProcessor 的新定期購檢查
相同 → 繼續接著驗證商店與商品頁,再把定期購主單映射到購物車 context。
不同 → 中止拋出 RegularOrderException("Other"),不會進入後續付款流程。
這是 Provider 這一道關卡的局部流程。程式在比對前已載入主單並檢查 ShopId、訂購狀態與 MemberId;若使用門市自取,還會先檢查門市是否可用。商店設定為舊版 Nine1 時,不執行這段 Provider 相等比對。
02商店已切換,舊來源仍送出請求時

例如商店設定已是 Nine1V2,這次請求卻宣告 GameBall,mweb 會在主單檢查階段拒絕這次建單。這表示請求來源與商店設定不符,不代表信用卡授權失敗。

商店設定Nine1V2
API 請求GameBall
檢查結果拒絕建單 · Other
03Provider 還決定主單怎麼載入

GetRegularOrderProcessor 先依商店設定的 Provider 選擇資料取得方式,取得主單後才做欄位驗證與上述比對。GameBall 與 Nine1V2 在這裡走同一條路。

商店 ProviderGameBall / Nine1V2
01以主單 ID 呼叫 GetCheckOutInfo 取得結帳資料。
02用 ShoppingCartNodeMappingToRegularOrderEntity 組成主單 Entity,再執行 Provider 相等比對。
商店 Provider其他值,包含 Nine1
01以主單 ID 呼叫 RegularOrderService.Get 讀取既有主單。
02商店 Provider 為舊版 Nine1 時,略過新定期購的 Provider 相等比對。
重點:Provider 在此決定主單的資料路徑,也用來核對這次請求是否屬於商店目前的定期購流程;實際可用付款方式仍由後續購物車與付款處理計算。
VIRTUAL CART · 資料如何成形

定期購資料如何變成虛擬購物車?

這一期訂單沒有經過會員手動加購物車。mweb 會把定期購請求、商店設定與商品頁資料組成購物車結帳所需的結構,再交給既有付款流程。

組車 Trace · 從 API 到購物車資料
API 入口SubscriptionOrderAutoGen
流程協調TradesOrderService
建立 ContextShoppingCartV2Service
執行組車 PipelineGetRegularOrder
產出 ShoppingCartClientEntity,交給付款 Context 建立流程
01資料從哪裡來,交到哪裡?

ShoppingCartV2Service 的定期購入口先建立 ShoppingCartV2Context,再依 GetRegularOrder 的註冊順序執行 Processor。下圖追蹤資料形成與交接。

本期 API 請求主單、商店與會員 ID;商品 SKU、價格與數量;收件、配送、付款與贈品資料。
商店設定從 ShopDefault 讀取目前的 RegularOrderProvider。
建立計算用 Context把請求欄位放進 RegularOrderData,連同商店 Provider、來源追蹤與購物時間建立 ShoppingCartV2Context。
轉成購物車商品資料GetRegularOrderProcessor 讀取並驗證主單,取得商品頁資料,再把主單價格、數量、交期與金物流條件寫入仿購物車結構。
補齊可結帳資料後續 GetRegularOrder Processor 準備贈品,檢查金物流、計算運費與限制,並預選結帳方式及計算配送日期。
shoppingCartContext.Data:ShoppingCartClientEntity組車成功後,TradesOrderService 將它交給 PayProcessService 建立付款 Context。
箭頭表示資料形成與交接方向。GetRegularOrderProcessor 在中途會依商店 Provider 選擇主單來源,並核對請求 Provider;詳細條件見前一個 tab。
02GetRegularOrderProcessor 實際做了什麼?

它是把定期購主單轉成購物車商品資料的核心節點。下方依 Process 的執行順序展開;後續運費計算與結帳預選由同一條 Pipeline 的其他 Processor 接手。

1 · 依商店 Provider 取得主單先決定主單資料從哪裡來,再形成 RegularOrderEntity。
GameBall / Nine1V2GetCheckOutInfo,再以請求欄位組主單。
其他 ProviderRegularOrderService.Get 讀取既有主單。
2 · 驗證主單與可售條件核對商店 ID、訂購中狀態、會員 ID;非舊版 Nine1 時,若為門市自取先檢查門市可用,並比對 Provider。接著執行 ValidateShop、ValidateSalePage。
3 · 生成購物車商品依主單的商品頁與 SKU 查商品資料,帶入主單價格、數量與下次出貨日,映射成 ShoppingCartClientEntity,並複製贈品需求。
4 · 補齊金物流並寫回 Context讀取商品頁金物流;非舊版 Nine1 依主單指定類型篩選。檢查選項、依溫層分組,補上識別碼、Provider 與結帳資訊,最後設為 context.Data。
若 RegularOrderData 不存在或主單 ID 為 0,這個 Processor 直接返回;商品資料缺失、售完或金物流不可用時的結果見下方「組車階段停下來」一節。
03主單欄位如何落到購物車?

商品頁提供可販售商品與原本金物流選項;定期購主單則保留本期的購買條件。轉換時兩邊資料會合併,不能只把 API request 原封不動交給付款流程。

主單商品條件商品頁與 SKU、主單價格、數量、下次預計出貨日
購物車商品節點查詢商品頁後,以主單價格與數量填值,設定交期,再依物流溫層建立 SalePageGroupList。
主單金物流條件PayProfileTypeDef、ShippingProfileTypeDef
可選的金物流先取得商品頁支援的選項;非舊版 Nine1 再依主單指定類型篩選,後續 Processor 計算可結帳組合。
定期購附帶資料贈品需求、Provider、結帳資訊
購物車交接欄位SubscriptionGiftItems、RegularOrderProvider;GameBall / Nine1V2 路徑另帶入 RegularOrderCheckoutInfo。
價格以主單為準:即使商品頁價格在定期購成立後改變,AssingShoppingCartInfo 仍把購物車商品價格設回主單價格。
04哪些情況會在組車階段停下來?
context.IsFinish = true查不到仿購物車商品頁資料,或映射後全部商品已售完,後面的 GetRegularOrder Processor 不再執行。
拋出購物車例外可售商品沒有可用金流、沒有可用物流,或物流同時出現多個溫層時,GetRegularOrderProcessor 會中止轉換。
這裡只列出轉換商品資料時的停止條件;主單與 Provider 的驗證也可能更早中止流程。
PAYMENT CONTEXT · 組裝與分流

虛擬購物車如何變成付款 Context?

虛擬購物車完成後,mweb 把它放進付款用的 Context,從已選的結帳方式判定後續流程,並補上本期定期購的收件與發票資料。

01從購物車到可用的付款 Context

TradesOrderService 將購物車交給 PayProcessService.GetProcessContextForRegularOrderPay。這段先建立付款資料,執行付款前置 Pipeline,回到外層後再覆寫定期購專用欄位。

輸入:ShoppingCartClientEntity 與會員 ID
1 · 確認購物車有商品群組購物車或 SalePageGroupList 為空時,拋出「購物車不得為空」例外。
2 · 建立 PayProcessContextEntity放入購物車與會員、產生 Context 識別碼,設定 V2 版本、拆單設定及定期購專用資料。
3 · 暫存並執行 GetPayProcess先以 UserDataHelper.Save 暫存 Context,再依序執行付款資料、Token、配送、驗證與遮罩的 Processor。
4 · 回到 TradesOrderService 補定期購資料以主單資料覆寫收件人;處理符合條件的馬來西亞發票資訊;請求有統編時,補上會員發票欄位。
PayProcessContextEntity帶著購物車、付款流程類型及定期購資料,交給後續建立訂單流程。
圖中順序依目前自動建單入口。付款 Context 的準備階段不會在這裡執行信用卡授權;正式建單由後續 CreateTradesOrder 流程處理。
02Context 裡先放了哪些資料?
購物車與會員ShoppingCartV2 放入虛擬購物車,ShoppingCartVersion 設為 V2,並設定 MemberId。IsOrdersSplitByQty 由商店設定取得。
本次 Context 識別新產生一組 GUID,同時寫入 UniqueKey 與 ContextId。這組識別碼用於暫存與後續載入。
定期購標記複製 RegularOrderProvider 與 RegularOrderCheckoutInfo。IsRegularOrderAutoGen 設為 true。
03已選付款方式如何變成流程類型?

GetPayProcessDataProcessor 從暫存資料還原購物車,讀取 SelectedCheckoutPayTypeGroup.StatisticsTypeDef,先設定 PayProfileType,再決定 PayProcessFlowType。以下列出主要對應。

購物車已選付款CreditCardOnce
CreditCardInstallment
PayProfileType沿用信用卡一次付清或分期類型
PayProcessFlowTypeCreditCardProcess
購物車已選付款CashOnDelivery
PayProfileTypeCashOnDelivery
PayProcessFlowTypeCashOnDeliveryProcess
購物車已選付款ATM
PayProfileTypeATM
PayProcessFlowTypeAtmProcess
購物車已選付款StorePay
PayProfileType取自已選超商配送類型
PayProcessFlowTypeShopProcess
StorePay 會依已選的 Family、SevenEleven、HiLife 或 OKmart 配送類型設定付款類型。其他付款方式依各自的 PayProfileType 分支決定流程;此處的分類還不是扣款。
04GetPayProcess Pipeline 做哪些準備?
入口:已暫存的 PayProcessContextEntity
1
還原資料並決定流程
載入 Context,設定配送與付款類型、Gateway 及流程類型。
GetPayProcessDataProcessor
2
補結帳與付款資料
處理商品頁備註、流程 Token、會員結帳資料與快速結帳資料。
GetSalePageMemoSettingsProcessorGetPayProcessTokenProcessorGetLastOrderInfoProcessorPayTypeExpressProcessor
3
檢查配送情境
處理海外配送、超商取貨付款與門市自取資料。
OverseaShippingProcessorCheckStorePayProcessorCheckLocationPickupProcessor
4
驗證與遮罩
檢查付款資料,再保存並遮罩需要保護的個資。
ValidateProcessDataProcessorMaskProcessDataProcessor
回傳付款 Context,外層再補本期定期購收件人與發票資料
四組依 PayProcessProcessorModule 的註冊順序排列,共列出 10 個 Processor。內部來源在 GetLastOrderInfoProcessor 不沿用一般結帳的上一筆訂單收件資訊;外層以本期定期購主單覆寫收件人。
CREATE TRADES ORDER

建立訂單後,這一期會怎麼付款?

PayProcessContext 已選好付款方式。CreateTradesOrder() 依 PayProcessFlowType 執行對應 Pipeline:一般信用卡、Stripe/Razer 信用卡與貨到付款,實際付款的節點並不相同。

01
付款方式如何分流?
PayProcessService.CreateTradesOrder(context)以 context.PayProcessFlowType.ToString() 選出已註冊的 Processor Pipeline
一般信用卡CreditCardProcessCreditCardOnce/CreditCardInstallment
先建立交易訂單,再檢查是否需要 3D 驗證,接著由授權 Processor 依商店設定的 Gateway 進行授權。
CreateTradesOrderProcessor→ThreeDSecureProcessor→AuthProcessor→CreateRegularOrderProcessor
Stripe/Razer 信用卡ThirdPartyProcessCreditCardOnce_Stripe/CreditCardOnce_Razer
同樣先建立交易訂單,付款交給第三方付款 Processor。該 Processor 呼叫 ITradesOrderPaymentService.ProcessPayment(),再由對應通道組織支付資料。
CreateTradesOrderProcessor→ThirdPartyPayApiProcessor→TransferOrderProcessor→CreateRegularOrderProcessor
貨到付款CashOnDeliveryProcessCashOnDelivery
建立交易訂單後走轉單與定期購處理。這條 Pipeline 沒有信用卡授權或第三方付款 Processor。
CreateTradesOrderProcessor→TransferOrderProcessor→CreateRegularOrderProcessor
圖中只列辨識分支所需的節點。三條 Pipeline 在建單前還會整理資料、驗證與計算金額,建單後也有訂單事件、額度與其他後續 Processor;箭頭表示註冊順序,不保證每次都能執行到最後。
02
定期購付款資料從哪裡來?

IsRegularOrderAutoGen 表示這次是定期購自動建單。它不直接決定走哪條 Pipeline,卻會影響支付通道組付款資料的方式。三種信用卡分支使用的保存資料也不同。

一般信用卡CreditCardOnce以下是 Nine1Payment 分支
來源:RegularOrderCheckoutInfo.credit_card_token 等已保存欄位↓ArrangeDataProcessor 寫入 PaymentInfo.CreditCardInfo↓AuthProcessor 依 CreditCardGatewayType 執行授權
StripeCreditCardOnce_Stripe
來源:RegularOrderCheckoutInfo 中的 CustomerId、PaymentMethod↓StripePayChannelService 組出 customer_id、payment_method,並設 off_session = true↓送往第三方付款服務,標示為會員未在線上的付款
RazerCreditCardOnce_Razer
來源:RegularOrderCheckoutInfo 中的 CreditCardToken 與持卡人聯絡資料↓RazerPayChannelService 組出 card_token、card_user_email 等欄位↓送往第三方付款服務;不重新組本次輸入的卡號與 CVV
一般信用卡的 Token 還原只描述程式中明確實作的 Nine1Payment 分支;其他 Gateway 不能直接套用同一組欄位。Stripe 與 Razer 的保存資料格式亦各自不同。
03
付款結果如何影響後續流程?
Pipeline 會依結果繼續或中斷。AuthProcessor 對授權失敗有取消訂單處理;ThirdPartyPayApiProcessor 遇到付款服務回報 Fail 會拋出流程狀態例外。因此,圖中的 TransferOrderProcessor、CreateRegularOrderProcessor 與 AfterOrderProcessor 是註冊的後續節點,不代表付款失敗後仍會執行。
Stripe 的 off_session 是請求模式。mweb 會在定期購自動建單且有保存結帳資料時送出這個旗標;實際付款結果仍取決於支付服務回應,不能把它視為每次都授權成功或永遠不需驗證。
核對程式:PayProcessService.cs、GetPayProcessDataProcessor.cs、PayProcessProcessorModule.cs、ArrangeDataProcessor.cs、ThirdPartyPayApiProcessor.cs、StripePayChannelService.cs、RazerPayChannelService.cs。
RECURRING CREDIT CARD

信用卡定期購,下一期沿用的是什麼資料?

本期自動建單會取回首次訂閱留下的結帳資訊,再交給對應金流組付款請求。保存格式依市場與支付通道而異;以下用馬來西亞 Razer 信用卡說明完整鏈路。

01
從首次訂閱到本期付款
首次訂閱結帳:建立定期購設定與保存的結帳資訊
1
保存首次結帳資料
CreateRegularOrderProcessor 在一般結帳建立定期購設定。對 GameBall/Nine1V2,它把 GetCheckOutInfo() 組出的資料寫入 RegularOrder_CheckoutInfo。馬來西亞 Razer 信用卡分支保存卡片 Token 與持卡人聯絡資料。
2
下一期讀回設定
外部供應商的 GetRegularOrderProcessor 透過 RegularOrderService.GetCheckOutInfo() 讀取保存內容,放進虛擬購物車的 RegularOrderCheckoutInfo。
3
帶入付款 Context
GetProcessContextForRegularOrderPay() 把購物車中的結帳資訊複製到 PayProcessContext,並設定 IsRegularOrderAutoGen = true。
4
建單後送出 Razer 付款請求
CreditCardOnce_Razer 選到 ThirdPartyProcess。Pipeline 先執行 CreateTradesOrderProcessor,再由 ThirdPartyPayApiProcessor 呼叫付款服務;RazerPayChannelService 使用保存資料組出 card_token 等欄位。
本期交易訂單與付款結果:回傳給定期購 Worker
這是「首次保存 → 本期讀取 → 建單與付款」的資料及執行順序。每期請求標記為內部來源,CreateRegularOrderProcessor 遇到內部來源會直接返回,不會為本期再建立一份定期購設定。
02
Razer 本期付款送哪些資料?

在 IsRegularOrderAutoGen 且為 Razer 信用卡通道時,RazerPayChannelService.GetPayExtendInfo() 讀取保存的 RegularOrderCheckoutInfo。它把 Token 與持卡人資料映射到付款請求,不採用一般結帳的卡號、效期與 CVV 欄位組法。

保存欄位 → Razer 付款請求欄位
credit_card_token映射為 card_token,交給支付通道辨識已保存的卡片。
credit_card_user_email映射為 card_user_email。
credit_card_user_fullname映射為 card_user_fullname。
credit_card_user_phone映射為 card_user_phone。
通道邊界:台灣一般信用卡由 CreditCardProcess 依 Gateway 處理;香港 Stripe 保存 customer_id 與 payment_method。因此「本期使用 Razer card_token」只適用於此處的 Razer 分支。
03
本期建單結果怎麼回到 Worker?

Worker 呼叫 SubscriptionOrderAutoGen 後,先判斷 API 是否成功,再看回傳的 OrderSlaveFlowStatus。這裡的 Pending 是 Worker 對本期明細的分類,不是另一個信用卡 Token 狀態。

SubscriptionOrderAutoGen 的回應先看 API ReturnCode 與 Data.Status,成功才讀 OrderSlaveFlowStatus
API 失敗
ReturnCode 非 API0001、資料缺失,或 Data.Status 非 Success。Worker 記錄本期建單失敗與錯誤原因。
建單成功,等待付款
OrderSlaveFlowStatus = WaitingToPay。Worker 保存訂單代碼,將本期明細標為 Pending,暫不當作付款完成。
建單成功,非待付款
API 成功且狀態不是 WaitingToPay。Worker 記錄本期成功,推進出貨週期並更新訂單對照。
mweb 的第三方付款服務也會依支付結果處理訂單狀態,例如 Pending 可使訂單成為 WaitingToPay。Worker 實際分流依據是 API 回傳的 OrderSlaveFlowStatus;兩層狀態不可直接畫成同一個值。
核對程式:mweb 的 CreateRegularOrderProcessor.cs、GetRegularOrderProcessor.cs、PayProcessService.cs、RazerPayChannelService.cs,以及 Worker 的 RegularCreateOrderJob.cs、RegularCheckPendingPaymentJob.cs。
CASH ON DELIVERY

貨到付款的這一期,mweb 會怎麼建單?

排程仍會建立本期交易訂單,但付款不在建單當下向信用卡通道請款。這條路徑的重點是建立訂單、排入轉單工作,以及把結果回報給定期購 Worker。

01
貨到付款的建單順序
本期虛擬購物車選擇 CashOnDelivery
1
選出貨到付款 Pipeline
GetPayProcessDataProcessor 將 PayProcessFlowType 設為 CashOnDeliveryProcess,CreateTradesOrder() 依此執行已註冊的 Processor。
2
整理資料並建立交易訂單
Pipeline 先整理、驗證、計算與映射訂單資料,再由 CreateTradesOrderProcessor 寫入本期交易訂單。訂單流程狀態起始預設為 WaitingToTrans。
3
排入 ERP 轉單工作
TransferOrderProcessor 建立轉單 Task。依設定排入 TransferOrderToERP 或 TransToERPTmp;這一步表示工作已排入,不表示 ERP 已完成轉單。
4
結束本期建單流程
CreateRegularOrderProcessor 看到內部來源會直接返回,不會再次建立訂閱主設定。Pipeline 接著執行後續訂單處理,API 回傳本期訂單識別資訊。
本期建立的是新的交易訂單,沿用既有的定期購設定
圖中保留與貨到付款有關的主要節點,省略優惠、贈品、點數與發票等共同處理。實際執行若遇錯誤,後續 Processor 可能不會執行。
02
訂單狀態與付款時點
mweb 建單時→建立交易訂單,流程狀態預設 WaitingToTrans。
轉單處理時→由背景 Task 接手 ERP 轉單。TransferOrderProcessor 本身只負責排入工作。
交付收款時→貨到付款的收款發生在後續交付流程,不是本次 mweb API 的線上信用卡授權。
付款邊界:CashOnDeliveryProcess 的註冊清單沒有 AuthProcessor 或 ThirdPartyPayApiProcessor。因此這次建單不會向 Razer 送 card_token,也沒有線上信用卡扣款步驟。
狀態判讀:原稿把貨到付款建單後固定寫成 WaitingToPay,與 CreateTradesOrderProcessor 的預設 WaitingToTrans 不符。若後續系統顯示待付款,應另看該階段的狀態欄位與更新來源。
核對程式:GetPayProcessDataProcessor.cs、PayProcessProcessorModule.cs、CreateTradesOrderProcessor.cs、TransferOrderProcessor.cs、CreateRegularOrderProcessor.cs。
ORDER STATE COMPARISON

同樣是本期建單,哪些地方真的不同?

付款方式先決定執行哪條 Pipeline;建立交易訂單時的初始狀態也各有規則。之後的授權或第三方付款結果可能再次更新訂單狀態,因此需要分清「剛寫入訂單」與「API 回傳時」。

01
建立訂單當下的差異
台灣一般信用卡CreditCardOnce
Pipeline:CreditCardProcess初始流程狀態:WaitingToAuth付款節點:AuthProcessor 依信用卡 Gateway 進行授權。
Stripe 信用卡CreditCardOnce_Stripe
Pipeline:ThirdPartyProcess初始流程狀態:沿用 WaitingToTrans 預設值。付款節點:ThirdPartyPayApiProcessor;付款服務可依結果更新狀態。
Razer 信用卡CreditCardOnce_Razer
Pipeline:ThirdPartyProcess初始流程狀態:定期購自動建單沿用 WaitingToTrans;一般結帳改設 WaitingToPay。付款節點:ThirdPartyPayApiProcessor;付款服務可依結果更新狀態。
貨到付款CashOnDelivery
Pipeline:CashOnDeliveryProcess初始流程狀態:沿用 WaitingToTrans 預設值。後續節點:TransferOrderProcessor 排入轉單 Task,沒有線上授權 Processor。
「初始流程狀態」指 CreateTradesOrderProcessor 建立 OrderSlaveFlow 時的 StatusDef。它不是整個付款流程的最終狀態,也不等於消費者畫面顯示的狀態。
02
建單後,哪一層會再改變狀態?
建立訂單→CreateTradesOrderProcessor 先寫入 OrderSlaveFlow.StatusDef。
執行付款→信用卡授權或第三方付款處理結果可更新流程狀態;第三方回報 Pending 時會寫入 WaitingToPay。
API 回傳→SubscriptionOrderAutoGen 從訂單流程查出 OrderSlaveFlowStatus,與交易訂單識別資訊一起回傳。
Worker 記錄本期→RegularCreateOrderJob 只在 API 成功且回傳 WaitingToPay 時,把本期明細分類為 Pending。
同名狀態的邊界:OrderSlaveFlow.StatusDef、面向會員的 StatusForUserDef,以及 Worker 的本期明細狀態是不同資料。只看到 WaitingToPay 這個字,不能直接推定它來自哪個欄位或表示哪個付款階段。
核對程式:mweb 的 GetPayProcessDataProcessor.cs、CreateTradesOrderProcessor.cs、TradesOrderPaymentService.cs、TradesOrderService.cs;Worker 的 RegularCreateOrderJob.cs。
REGULAR ORDER TRACING

同一期請求重送,mweb 怎麼找回已建的訂單?

RegularOrderTracing 用呼叫端提供的 TraceId 記錄一次自動建單嘗試。它保存處理狀態與建立出的交易訂單識別資訊,讓已成功的同一請求可以直接回傳原結果。

01
同一個 TraceId 再進來時
SubscriptionOrderAutoGen 收到 TraceId先執行 BlockDuplicateRequest,再查詢 RegularOrderTracing
查無紀錄
插入 StatusDef = New,記下 RegularOrderId、TraceId、執行日期與預計出貨日,再組購物車、付款 Context 並建單。
已有 Success
跳過重新建單。用 Tracing 保存的 TG/TS 識別資訊組成功回應,並查詢目前的 OrderSlaveFlowStatus。
已有其他狀態
Controller 沒有在這裡直接回傳;它繼續執行本次建單流程。因此 New 或 Fail 不能視為「已被永久擋下」。
短時間重複請求由 BlockDuplicateRequest 處理;持久的結果重用只見於 Tracing 已是 Success 的分支。兩者作用時點不同。
02
Tracing 什麼時候更新?
第一次收到請求→插入 New;ExecutedDate 是當天,ExpectShippingDate 來自請求的 NextExpectShippingDate。
建單方法返回→CreateTradesOrder() 返回後,更新為 Success,並寫入建立出的 TG/TS 代碼與 ID。
一般例外→若查得到這筆 Tracing,Controller 更新為 Fail,回傳失敗結果。
狀態邊界:Tracing 的 Success 代表這次 CreateTradesOrder() 已返回且訂單識別資訊已記錄,不等於第三方付款一定完成。本期交易訂單仍可能回報 WaitingToPay,由 Worker 另外分類為 Pending。
例外分支:NoMoreElmahException 的 catch 直接回傳錯誤,沒有在該分支更新 Tracing;原稿把所有例外都畫成 Fail 並不精確。
03
它保存哪些對照資料?
這次請求TraceId、RegularOrderId。Worker 建立 API 請求時,以本期明細的 RodTxid 作為 TraceId。
期別時間ExecutedDate、ExpectShippingDate,用來追查這次何時執行、預計何時出貨。
處理狀態StatusDef 記錄 New、Success 或 Fail。它描述自動建單嘗試,不是信用卡交易狀態。
交易訂單TradesOrderGroupId/Code、TradesOrderSlaveId/Code,供成功重送時找回原訂單。
RegularOrder→長期訂閱設定,保存商品、週期、收件與結帳資訊。
RegularOrderTracing→本次自動建單的狀態與交易訂單對照。
TradesOrderGroup/Slave→本期實際建立的交易訂單與明細。
重送的界限:如果交易訂單已寫入,但 Tracing 尚未更新為 Success,僅憑此處的 Success 回放分支無法證明「任何時點重送都絕不重複建單」。排查時仍需對照交易訂單與 Tracing。
核對程式:TradesOrderV2Controller.SubscriptionOrderAutoGen()、RegularOrderService.cs、TradesOrderService.GetAutoGenResponseEntity()、Worker 的 RegularCreateOrderJob.cs。