Skip to content

v3.5.20 綠界物流:COD 改單後靜默不代收、前台看不到宅配托運單號

Choose a tag to compare

@j7-dev j7-dev released this 16 Sep 06:09
· 36 commits to master since this release

本版修正兩個綠界物流的問題,其中 #132 會直接造成商家金錢損失。

一、貨到付款改單後重建物流單,代收貨款靜默消失(#132)

貨寄出、買家到店取走,但綠界沒有代收貨款,而後台從頭到尾沒有任何提示或警告,商家通常要到對帳才發現。

客戶實際回報的案例,同一筆訂單改單後重開物流單,綠界後台匯出的紀錄:

第一張 第二張(改單後)
綠界物流編號 49811043 49814128
訂單金額 689 680
純配送/貨到付款 貨到付款 純配送
物流代收款項 689 0
物流狀態 訂單超過驗收期限 買家已到店取貨

WooCommerce 訂單本身的付款方式自始至終都是「貨到付款」。

根因:代收判斷被鎖在第一張物流單,且欄位沒有預設值

if (count($shipping_list) == 0) {        // ← 只有第一張物流單才會進來
    if ($order->get_payment_method() == 'cod') {
        $args['IsCollection'] = 'Y';
        ...
    }
}
if ($collection == true) {               // ← 只有選「代收貨款」動作才補回來
    $args['IsCollection'] = 'Y';
    ...
}

第二次建立時 count($shipping_list) 已不是 0,整段自動判斷被跳過。若管理員選的是一般的「取得新的綠界物流編號」($collection 為預設 false),IsCollection 從頭到尾沒有被設定,而 $args 初始陣列也不含這個 key —— 欄位完全不在送往綠界的 payload 裡。

綠界官方文件(developers.ecpay.com.tw/8809.md)載明 IsCollection 為選填、未帶時預設 N,所以綠界以純配送建單,不報錯、不警告。後台兩個動作的名稱(「取得新的綠界物流編號」/「…(代收貨款)」)差異不明顯,很容易選錯。

欄位缺席還有一個連帶症狀:程式後續讀取未定義的 $args['IsCollection'] 寫入訂單 meta,PHP 8 噴 Undefined array key warning 並存入 null,後台 meta box 的代收欄因此恆顯示 No —— 這是商家唯一能看到的線索,但幾乎沒人會注意。

修正內容

  • $args 初始陣列明確帶入 IsCollection = 'N'、CollectionAmount = 0,杜絕欄位缺席
  • 代收判斷改為 true === $collection || 'cod' === 付款方式,不再受「是否為第一張物流單」影響
  • 已有物流單又建立代收單時,寫入訂單備註「此訂單已有物流單,本次再次建立代收貨款物流單,請確認代收金額是否重複。」

取捨說明:原本的 count == 0 護欄用意應是「補寄第二箱時不重複代收」。改動後這個情境會變成第二箱也帶代收,故補上訂單備註提醒。之所以選擇這個方向 —— 靜默不代收是純損失且到對帳才知道,重複代收商家當場看得到備註、也能處理。

二、多件包裹取號時第一、二張都代收全額(附帶發現)

if ($i > 01) {     // 01 是八進位字面值,實際等於 1

no_count >= 3 的多件包裹取號時,第 1、2 張都會帶全額 CollectionAmount,與 specs/ecpay-shipping.feature 的「僅第一張為代收貨款」不符。這是與 #132 相反方向的錢的問題。已改為 $i > 0。

三、客戶在訂單查詢頁看不到物流單號(#133)

前台「我的帳戶 → 檢視訂單」中,「綠界物流資訊/物流單號」的標題出得來、單號欄位空白,但同一筆訂單在後台看得到單號。

根因:宅配托運單號在 BookingNote,前台只讀超商欄位

不是 meta key 不符,也與 HPOS 無關(前台已使用 $order->get_meta())。

綠界宅配(黑貓/郵局)的托運單號存在 BookingNote,超商取貨才是 PaymentNo + ValidationNo。前台只處理超商那兩個欄位,而且用 isset() 判斷 —— 宅配時這兩個 key 一定存在、值為空字串,isset() 仍為 true,於是陣列被塞進一個只有空白的字串,count() > 0 成立,標題與表格照印而儲存格空白。

後台訂單列表與 meta box 都有 BookingNote 分支,唯獨前台沒有,前後台因此表現不一致。

修正內容

改前  ┌──────────┐        改後  ┌─────────────┐
      │ 物流單號 │              │ 物流單號    │
      ├──────────┤              ├─────────────┤
      │          │  ← 空白      │ 90012345678 │  ← BookingNote
      └──────────┘              └─────────────┘
  • isset() 改為 ! empty(),空字串不再視為有值
  • 新增 BookingNote 分支顯示宅配托運單號
  • 超商 B2C 只有 PaymentNo 時以 trim() 去掉尾隨空白
  • 三個欄位皆空時略過整筆,不再出現「孤零零的標題配空白格」

刻意不加「退回顯示 AllPayLogisticsID」的 fallback:該編號是綠界內部交易編號,客戶拿它到超商或黑貓查不到,顯示出來只是把空白換成噪音。

驗證

新增 11 個 PHPUnit 整合測試:

  • tests/phpunit/integration/EcpayShippingCollectionTest.php(6 個,含 #132 迴歸與八進位迴歸)
  • tests/phpunit/integration/PublicOrderShippingNumberTest.php(5 個,含 #133 迴歸、B2C 尾隨空白、全空不輸出)

與既有 EcpayCallbackTest / EcpayRefundTest / ShippingMethodTest 一起執行:OK (37 tests, 115 assertions)。

紅燈驗證:把兩個修補檔還原成修復前版本重跑,7/11 個新測試如預期失敗,確認測試確實鎖住這兩個 bug 而非空測。phpcs 對照修改前 baseline 無新增違規。

升級後注意

  • 貨到付款訂單重建物流單時,無論選哪一個後台動作都會代收貨款。若原本習慣用「取得新的綠界物流編號」來刻意建立不代收的補寄單,改版後需留意新增的訂單備註並自行確認金額
  • 前台原本空白的物流單號欄位,宅配訂單會開始顯示托運單號;尚未取得單號的訂單則整塊不顯示(原本會顯示空白表格)
  • 其他物流商(藍新、速買配、立吉富)已檢查,無相同 pattern,行為不變

修復 #132、#133