購物車系統開發最容易被低估的地方,是把「顧客看到付款完成」當成訂單已經可以出貨。實際上,瀏覽器跳回商店、金流從伺服器通知、庫存被保留,以及後台將訂單改成已付款,可能在不同時間發生。若規格只有「串接金流與庫存」,重複通知、付款頁被關閉或最後一件商品同時被兩人購買時,就沒有一致的處理依據。
需求書應先拆開購物車、訂單、付款與庫存四種資料。購物車是顧客仍可修改的選購內容;送出結帳後產生訂單快照;付款是外部交易的狀態;庫存則記錄可售、保留與實際扣減。四者彼此關聯,但不能用一個「完成」欄位代替。
購物車送出時先建立不可變的訂單快照
商品主檔會改價、下架或換名稱,因此訂單成立時應保存當下的品名、規格、單價、數量、折扣、運費與總額。金流請求要引用訂單編號與付款嘗試,而不是每次都重新讀取可能已變動的購物車。顧客返回上一頁再按一次付款時,系統才能判斷是沿用未完成嘗試、建立新嘗試,還是拒絕重複送出。
後台也要看得到同一訂單的多次付款嘗試。每次請求保存送出時間、金額、外部交易識別與目前結果,但訂單只在符合規則的成功通知後轉態。這能避免客服只看顧客截圖便手動把訂單改成已付款,也能在對帳時追查「訂單一筆、付款嘗試兩次」的情境。
庫存要區分現有、可售與已承諾
Shopify 的庫存狀態說明把庫存分為 On hand、Available、Committed、Unavailable 與 Incoming;其中 Available 是仍可銷售的數量,Committed 則是已為訂單保留、不能再出售的數量。這個分類不必原樣複製,但它證明「倉庫裡有幾件」與「網站還能賣幾件」不是同一數字。
客製系統要明定何時保留庫存。若顧客只要進購物車就保留,長時間未結帳會占住商品;若付款成功才扣庫存,熱門商品可能在付款期間超賣。常見折衷是建立有限時的訂單保留,逾時後釋放,但保留時間、付款中的延長條件,以及晚到的成功通知如何處理,都必須由營運方決定。
驗收可用「只剩一件」測試:兩個瀏覽器同時送出訂單,確認最多只有一筆取得有效保留;另一筆應看到缺貨、候補或人工處理結果。接著讓第一筆逾時,確認庫存真的釋放,而且舊付款頁不能在沒有檢查的情況下把已釋放商品重新標成可出貨。
付款狀態以伺服器通知為準,不依賴返回頁
綠界的付款結果通知文件區分伺服器端的 ReturnURL 與顧客瀏覽器接收的 OrderResultURL,並指出兩者沒有固定先後順序。文件也要求檢查 CheckMacValue、交易狀態,以及該筆付款通知是否已經處理過;若未正確回應,通知還可能重發。
因此,顧客回到「付款完成」頁,只適合顯示查詢中的結果,不能單靠前端導頁觸發出貨。接收端要先驗證通知、比對訂單與金額,再以外部交易識別或通知特徵做去重;相同成功通知重送時,結果仍應是同一筆付款,不可再扣一次庫存、再發一次點數或建立第二張出貨單。
系統也應保留「已收到但待確認」「驗證失敗」「金額不符」「模擬付款」等例外。綠界文件明確提醒,模擬付款通知不是實際付款,不應據此出貨。這些狀態應進異常佇列,由有權限的人處理,而不是把所有非成功結果統稱為付款失敗。
用 MORIÉ 案例把前台動線轉成後台驗收
MORIÉ 森澄研展示案例包含商品分類、篩選、收藏、購物車與站內結帳。可沿著案例的購物動線建立驗收資料:顧客把兩種保養品加入購物車,結帳時其中一項只剩一件;系統應保存訂單快照、保留正確規格與數量,並讓後台看見付款嘗試和庫存狀態。
再測試顧客付款後立刻關閉頁面、金流通知比導回頁晚到,以及相同通知重送。前台重新查詢訂單時應得到後台確認的狀態;後台則只產生一次庫存扣減與後續作業。MORIÉ 是展示作品,不代表真實商店的營運成果;它提供的是可操作的選購流程,方便把抽象規格變成具體測試步驟。
把失敗路徑寫進交付清單
正式驗收至少涵蓋價格在結帳前變更、最後一件同時購買、付款逾時後才成功、顧客未回站、重複成功通知、通知驗證失敗、金額不符、庫存服務暫時失敗,以及人工補單。每個情境都要列出訂單、付款、庫存、通知與出貨的預期狀態。
購物車系統開發不是讓按鈕能跳到金流頁就結束。先把訂單快照、庫存保留、付款嘗試與伺服器通知拆開,再用重複和亂序事件驗收,才能確保顧客看見的結果、後台的交易紀錄與倉庫能出貨的數量維持一致。