transactions 狀態變動
文件狀態:草稿 / 已補 quote bid contact charge 排查主線
最後驗證:2026-05-07
來源:Common Process Documents、Lib/Model/Transaction.php::logQuoteBidTxn、Lib/Model/QuoteBid.php contact charge trace
目的
transactions 是交易與扣款紀錄主表。它用 class + foreign_id 連回不同 domain object,其中 quote bid contact charge 會使用:
transactions.class = QuoteBid
transactions.foreign_id = quote_bid_id這裡專注 table 狀態判讀與跨表關聯;wallet/card/TapPay/Stripe 的完整分支規則放在 付款與扣款流程/quote_bid_contact_charge。
search_add 主線通常不是扣款主線。若從 search_add trace 到 transaction,需先確認是否已進入後續 contact provider / narrow match accept / payment flow。
不回答什麼
- 不重寫 wallet / card / TapPay / Stripe 的完整分支。
- 不記單次付款 response 或 staging 測試 ID。
- 不把 Redis lock 當成 transaction 狀態;Redis 只保護併發或短期狀態。
它連到哪些資料
users:交易 user,quote bid contact charge 通常是 provider payer。quote_bids:class = QuoteBid時foreign_id指向 bid。quote_requests:可透過 quote bid 回到 request。stripe_customers:card / auto quote customer 狀態。- TapPay / Stripe logs:金流實際 response 與
rec_trade_id/ charge id。 - application log:
processWantToContactProvider與logQuoteBidTxn是付款排查第一入口。
建議閱讀順序
- quote_bid_contact_charge
- Log channel 與 error code 索引
- quote_user_subscription_log_id
欄位/class.md欄位/foreign_id.md欄位/transaction_type_id.md欄位/real_pay_date.md欄位/stripe_charge_id.md流程/quote_bid_contact_charge.md關聯/quote_bids.md關聯/users.md
核心觀念
transactions 不能只看是否有 row。要區分:
有 transaction row
已付款 transaction
未付款 / debt transaction
wallet transaction
card / TapPay / Stripe transaction常用判讀:
real_pay_date 有值 -> 通常代表已付款
stripe_charge_id 有值 -> 可能是 Stripe charge id,也可能是 TapPay rec_trade_id
quote_bids.quote_user_subscription_log_id -> 指向相關 transaction id,但仍要看 real_pay_date 判斷付款狀態Quote bid contact charge 主線
provider 正式 contact 一筆 quote / new lead 時,常見 trace 是:
QuoteBid::processWantToContactProvider()
-> Redis payoff lock
-> QuoteBid::processWantToContactCharge()
-> wallet / card / TapPay branch
-> Transaction::logQuoteBidTxn()
-> transactions
-> quote_bids.quote_user_subscription_log_id重點:
- Redis payoff lock 只保護 provider 同一時間扣款,不代表扣款成功。
- 拿不到 lock、Redis 斷線、付款失敗、transaction guard 是不同層級。
processWantToContactProviderlog 通常比transactions更接近根因。logQuoteBidTxnlog 代表流程已走到 transaction 寫入前後。- 沒有 transaction row 時,不要先判斷 transaction 壞掉;可能是 guard、付款方式或 Redis lock 先擋住。
什麼情況不會建立 transaction
常見不建立成功 transaction 的情況:
| 情況 | 常見線索 | 優先查 |
|---|---|---|
| provider / request / bid guard 擋住 | API error、沒有 contact 狀態 | endpoint / business flow |
| provider 資格或封鎖限制 | error 690 / 251 / 256 | processWantToContactProvider log |
| wallet 不足且無 card / prime | error 10,要求設定信用卡 | processWantToContactProvider log |
| TapPay / card 失敗 | error 211 或 charge error | payment provider log / application log |
| transaction amount 不合法 | logQuoteBidTxn | transactions 寫入前 context |
| Redis lock 擋住重複扣款 | lock / retry log | Redis lock key、application log |
quote_user_subscription_log_id
quote_bids.quote_user_subscription_log_id 是 quote bid 對應交易紀錄的重要連結:
quote_bids.quote_user_subscription_log_id = transactions.id但這個欄位不能單獨代表「付款成功」。
判斷時至少一起看:
transactions.real_pay_date
transactions.real_pay_amount
transactions.amount
transactions.transaction_type_id
transactions.stripe_charge_id
quote_bids.is_paid_for_subscriptionstripe_charge_id
這個欄位名稱沿用舊 schema,不一定只存 Stripe charge id。
在 TapPay pay-by-prime 成功時,可能存:
TapPay rec_trade_id所以看到 stripe_charge_id 有值時,要搭配 payment branch / provider log 判斷它是哪個 provider 的交易識別。
排查順序
付款或 contact 異常時,建議順序:
- 查 application log。
channel = processWantToContactProvider
channel = logQuoteBidTxn
channel = getCheckConnect- 查
quote_bidscontact / transaction link。
SELECT
id,
provider_user_id,
quote_request_id,
is_want_to_contact_provider,
contact_provider_on,
is_paid_for_subscription,
quote_user_subscription_log_id,
total_site_fee,
narrow_status_id,
quote_status_id,
provider_status_id
FROM quote_bids
WHERE id = <quote_bid_id>;- 查
transactions。
常用 SQL
SELECT
id,
created,
user_id,
foreign_id,
class,
transaction_type_id,
amount,
real_pay_amount,
real_pay_date,
stripe_charge_id,
wallet_balance
FROM transactions
WHERE class = 'QuoteBid'
AND foreign_id = <quote_bid_id>
ORDER BY id DESC;- 如果有
quote_user_subscription_log_id,也用 transaction id 反查一次:
SELECT
id,
created,
user_id,
foreign_id,
class,
transaction_type_id,
amount,
real_pay_amount,
real_pay_date,
stripe_charge_id,
wallet_balance
FROM transactions
WHERE id = <quote_user_subscription_log_id>;- 若牽涉 Redis lock,再回到 Redis 設定與 key pattern。
Redis 設定與用法來源見 Redis。Redis key 通常有 TTL,key 不存在不等於流程沒跑過。
適合優先補的文件
欄位/real_pay_date.md:paid / unpaid 的判斷。欄位/stripe_charge_id.md:Stripe charge id 與 TapPayrec_trade_id共用欄位的注意事項。流程/quote_bid_contact_charge.md:從 quote bid contact 到 transaction 的落點。關聯/quote_bids.md:bid 如何透過quote_user_subscription_log_id對回 transaction。