SearchAdd Bid Finalize

快速結論

這段負責把已建立的 bid 補成前端可用的報價內容,例如 price note、pricing unit、detect content、activity、cache。

current 入口:

SearchAddHandler::handle()
-> QuoteBidFinalizer::finalize()

新舊程式對應

Current Legacy

主要入口:

/Users/mattsu/Documents/Site/get-lancer-docker-2/get-lancer/app/Plugin/Quotes/Model/QuoteService.php::handleAutoQuote()
legacy 區段職責
handleAutoQuote()auto quote bid 後處理。
pricing / price note補 quote amount、pricing unit、price note。
detect / activity / cache補內容偵測、activity、cache queue。

Current PHP 8.2

current 位置職責
Lib/SearchAdd/SearchAddHandler.php:317-320呼叫 QuoteBidFinalizer::finalize()
Lib/SearchAdd/QuoteBidFinalizer.phpbid finalize orchestration。
Lib/SearchAdd/BidPricingResolver.phppricing unit / quote amount / price note。
Lib/SearchAdd/BidDetectContentWriter.phpbid detect content。
Lib/SearchAdd/BidActivityWriter.phpbid activity。
Lib/SearchAdd/BidCacheQueueWriter.phpcache queue。

行號對照

new 行號對應 legacy職責
SearchAddHandler.php:317-320QuoteService.php:3155-3158matcher 建 bid 後呼叫 bid finalize。
QuoteBidFinalizer.php:43-53QuoteService.php:1567-1595讀 request 與要 finalize 的 bids;沒有 bid 時不處理。
QuoteBidFinalizer.php:56-63QuoteService.php:1597-1648, 1663-1683逐筆 bid 讀 service category,準備 pricing context。
BidPricingResolver.php:27-76QuoteService.php:1624-1655, 1679-1857決定 price_display、price_note、quote_amount、pricing_unit、pricing 成功旗標。
BidPricingResolver.php:78-140QuoteService.php:1624-1628, 1737-1752, 1853-1860requestor lang、consumer name、default price display/note、consumer name replacement。
BidPricingResolver.php:175-204QuoteService.php:1638-1648, 1737-1747從 pricing form submission 反推 pricing unit。
BidPricingResolver.php:213-260QuoteService.php:1679-1724precise pricing:quote pricing route、form submission order、getPrice。
QuoteBidFinalizer.php:66-89QuoteService.php:1892-1929組 quote bid update 欄位;narrow 不提升狀態、不帶 price_note。
QuoteBidFinalizer.php:98-100QuoteService.php:1931更新 quote_bids
QuoteBidFinalizer.php:102-104QuoteService.php:1932-1936非 narrow 寫 SubmitQuote activity。
QuoteBidFinalizer.php:106-112QuoteService.php:1864-1890price note detect content。
QuoteBidFinalizer.php:115-117QuoteService.php:1942-1945寫 cache queue 更新 counter。
QuoteBidFinalizer.php:119QuoteRequestsController.php:3345-3383, 3389-3398reload bids,補 response 需要的 service / attachment data。

第 6 組:excluded critical pricing option(已完成,commit 5a1cd38b

差異與根因

Current Legacy cfa660b0c

  • QuoteFormField.php:373-432input.type != large_imageexclude_pricing = 1 的 option,在 is_show_exclude = false 時直接 continue;critical 沒有例外。
  • QuoteService.php:1644-1653,1698-1705:search_add 與 copy 都把上述 pricing form fields 送進 submission order 與 precise pricing。
  • QuoteServiceCategory.php:2126-2187:只有答案完整等於仍存在的 option title 才形成 route;含 | 不做前段 fallback。
  • 這是 98c518ca3(BAC-3592 rollback)後的現行規則。

修正前 PHP 8:

  • QuoteFormField.php:533-581:shared method 對 critical 保留 excluded option,並標記 is_exclude=1
  • BidPricingResolver.php:175-203,213-269:pricing unit 與 precise pricing 都直接使用 shared method 的結果,所以 excluded critical answer 仍可能形成 route。
  • 本地 DB category 159/field 2227 可重現:其他(order 3)仍留在 format_options

修正後 PHP 8:

  • Lib/Model/QuoteFormField.php:534-546:新增 default false 的 scoped 參數 $exclude_critical_pricing_options;啟用時改用 _exclude_critical Redis hash field。
  • Lib/Model/QuoteFormField.php:583-591:scoped 模式下,excluded critical option 與 Legacy 一樣直接 continue
  • Lib/SearchAdd/BidPricingResolver.php:185-191,240-246:pricing unit 與 precise pricing 兩個入口都明確啟用 scoped 模式。

Shared caller 與 scoped 決定

QuoteFormField::getPricingFormField() 另有 QuoteServiceCategoryQuoteServiceCategories endpoint caller,不直接改預設行為。

已新增 optional scoped 參數:

getPricingFormField(..., $exclude_critical_pricing_options = false)
  • 預設 false:其他 PHP 8 caller 維持現況。
  • BidPricingResolver 的兩個呼叫明確傳 true,對齊 current Legacy。
  • scoped 結果使用獨立 Redis hash field suffix,不能覆蓋 default caller 的既有 cache。
  • BidPricingResolver 同時由 search_add 與 quote request copy 的 QuoteBidFinalizer 使用;Legacy 兩條流程都進同一個 handleNewQuoteRequestAutoQuote()->handleAutoQuote(),因此 scope 一致。

預期流程與結果

excluded critical answer
-> scoped pricing form 不含該 option
-> submission order 不產生 critical order
-> 不可進該 critical precise-pricing route
-> 沿用 Legacy fallback:quote_amount=0、需要更多資訊/現場評估 flag=1

本組只改 pricing form read/cache field 與既有 bid finalize 計算;不新增 DB write、log、queue、activity、payment、notification、response 欄位或 config。

測試結果

Core 2 tests / 30 assertions

  • category 280 正常 precise pricing 仍得到 quote_amount=1350
  • category 159/critical field 2227其他;即使 provider 的 quote_pricing.critical.3 有價格 999,仍不可使用該 price note 或 route,結果為 quote_amount=0flat_rate_at=0、兩個 more-information/on-site flag 為 1

Other 4 tests / 50 assertions

  • default shared caller 仍保留 其他,確保未擴大修改。
  • scoped caller 移除 其他,但保留正常 critical options。
  • scoped/default cache field 互不污染。
  • category 159 negotiable route、fixed pricing fallback/detect content、narrow bid regression 不變。

整支 SearchAddStep6IntegrationTest6 tests / 80 assertions;全部已歸到 coreother。既有固定 session fixture 改為測試自行建立與清理的暫時帳號,避免 session 過期造成假失敗。

Side Effects

同步可能更新:

  • quote_bids
  • bid detect content 相關資料
  • quote_activities
  • cache_queues

不可改變的契約

  • finalize 只處理已建立 bid。
  • narrow bid 不應被 finalize 錯誤提升成 auto quote sent 狀態。
  • pricing / price note / pricing unit 要和 legacy 相同。
  • finalize 後仍可能再進 special post-flow。

Verification

主要測試:

docker exec -w /project-data cd63f9147e8d \
  vendor/bin/phpunit tests/SearchAddStep6IntegrationTest.php --group core
 
docker exec -w /project-data cd63f9147e8d \
  vendor/bin/phpunit tests/SearchAddStep6IntegrationTest.php --group other

PHP 8.2 結果:Core 2 tests / 30 assertions、Other 4 tests / 50 assertions,全數通過。三個修改檔案 php -l 均通過。

待確認 / 風險

  • staging/production 的 category/field 資料仍需上線前確認;本組不需要新增 deployment config。