Skip to content

fix(hpos): PayNow transaction_id 與 RY 物流 shipping_address_1 改用 setter 才能寫入#113

Open
lukehsuhao wants to merge 1 commit into
zenbuapps:masterfrom
lukehsuhao:fix/hpos-core-field-writes
Open

fix(hpos): PayNow transaction_id 與 RY 物流 shipping_address_1 改用 setter 才能寫入#113
lukehsuhao wants to merge 1 commit into
zenbuapps:masterfrom
lukehsuhao:fix/hpos-core-field-writes

Conversation

@lukehsuhao
Copy link
Copy Markdown
Contributor

Closes #112.

摘要

接續 #110 / #111 的 LINE Pay HPOS 修正後,掃描整個 codebase 找到另外 2 處對核心欄位用 update_meta_data() 寫入,HPOS 下會被靜默丟棄的 bug:

  1. PayNow 付款:IPN 回應時 _transaction_id 寫不進去,訂單沒有 transaction_id(影響退款、對帳)
  2. RY 物流:選 CVS 取貨點後 _shipping_address_1 寫不進去,shipping address 不會更新

完整影響說明、掃描範圍、為什麼其他 5 處被守護的 branch 不算 bug,請看 #112

變動

兩處最小變動,僅換 setter:

 // includes/paynow-payment/includes/gateways/class-paynow-payment-response.php
 $order->update_meta_data( '_paynow_tran_id', $buysafe_no );
 $order->update_meta_data( '_paynow_tran_status', $tran_status );
-$order->update_meta_data( '_transaction_id', $buysafe_no );
+// HPOS 下 `_transaction_id` 是 wc_orders.transaction_id 欄位,
+// 透過 update_meta_data 寫入會被靜默丟棄,必須使用 setter。
+$order->set_transaction_id( $buysafe_no );
 // includes/ry-woocommerce-tools/woocommerce/shipping/ry-base.php
 // HPOS 相容:使用物件方法操作 meta
 $shipping_address = $order->get_address( 'shipping' );
-$order->update_meta_data( '_shipping_address_1', wc_clean( wp_unslash( $_POST['_shipping_cvs_store_address'] ) ) );
+// `_shipping_address_1` 是 wc_order_addresses 的核心欄位,
+// HPOS 下 update_meta_data 會被靜默丟棄,必須用 setter。
+$order->set_shipping_address_1( wc_clean( wp_unslash( $_POST['_shipping_cvs_store_address'] ) ) );
 $order->update_meta_data( '_shipping_address_index', implode( ' ', $shipping_address ) );
 $order->save();

_shipping_address_index 維持原本 update_meta_data(這個是 WC 的 search index meta、不是核心欄位)。
其他 update_meta_data 行不動(PayNow custom meta _paynow_tran_id_paynow_tran_status 等都還是 meta,不是核心欄位)。

為什麼這樣修

WC_Data::update_meta_data() 把資料放進物件的 $meta_data 陣列,等 save() 時 data store 持久化。
HPOS 的 data store(OrdersTableDataStore)在 update_post_meta_from_object / 對應的 save flow 裡面會以 internal_meta_keys 過濾掉所有「實際對應到欄位」的 key — 包含 _transaction_id_shipping_address_1_billing_*_payment_method 等。
被過濾掉的 key 不會:

  • 寫進 wc_orders_meta 表(不是 meta)
  • 寫進 wc_orders / wc_order_addresses 對應欄位(沒有 routing 邏輯)

所以是 silent drop。對應的 setter(set_transaction_idset_shipping_address_1 等)才會更新底層 prop,save() 時走「欄位儲存」路徑、寫進去 column。

測試方法

兩處都要實際 HPOS + 站台環境才測得到(受害情境):

  • PayNow:HPOS + 啟用 PayNow 付款 → 客人完成付款 → 收 IPN → 看 wc_orders.transaction_id 欄位 / $order->get_transaction_id() 是否有值
  • RY 物流:HPOS + 啟用 RY 系列 CVS 取貨 → 客人選店點 → 看 wc_order_addresses 裡 shipping row 的 address_1 是否變成店點地址

我這邊只有 LINE Pay 環境(已驗證 #111),這 2 處沒有實際站台情境驗證,但邏輯是 #111 的鏡像(讀取面 vs 寫入面),改法是 WC HPOS 的 canonical pattern。


🤖 Generated with Claude Code

`_transaction_id` 與 `_shipping_address_1` 在 HPOS 下分別是 wc_orders 與
wc_order_addresses 的欄位,不是 meta。透過 `WC_Order::update_meta_data()` 寫入
會在 save 階段被內建的 internal_meta_keys 過濾掉、靜默丟棄,必須改用對應 setter。

修正兩處:

1. PayNow 付款 IPN 回應將收款編號寫入 `_transaction_id`(class-paynow-payment-response.php:206)
   → 改用 `WC_Order::set_transaction_id()`
   影響:HPOS 下 PayNow 訂單付款成功後,order 的 transaction_id 為空,後續退款/對帳/
   `WC_Order::get_transaction_id()` 全部拿不到值。

2. RY 物流 CVS 取貨點地址寫入 `_shipping_address_1`(ry-base.php:181)
   → 改用 `WC_Order::set_shipping_address_1()`
   影響:HPOS 下選擇超商取貨後,店點地址不會回寫進訂單的 shipping address。

掃描範圍是針對 woomp 全部 PHP 檔案,剩下 5 處對核心欄位的 update_meta_data 都被
`version_compare(WC_VERSION, '5.6.0', '<')` 守護,woomp 3.5.x 已要求 WC 7.1+,
為 dead-code branch、不影響執行;本 PR 不動這些。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] HPOS 下 PayNow 付款的 transaction_id 與 RY 物流 shipping_address_1 寫入靜默失敗

1 participant