QuoteBids Add Consumer Survey

API:

POST /quote_bids/add_consumer_survey/quote_bid_id:{quote_bid_id}.json

quote_bid_idquote_bids.id。web-app 使用 consumer session token,body 是 FormData

功能說明

consumer 在案件後續填寫實際支付 / 預算問卷時呼叫此 API。這支只新增或覆蓋 quote_consumer_surveys,不更新 bid 狀態,也不建立 activity、queue、transaction 或通知。

成功 response:

{"error":0,"status":"success"}

快速結論

  • actor:quote request owner consumer session。
  • legacy API:QuoteBidsController::add_consumer_survey()
  • legacy path:/quote_bids/add_consumer_survey/quote_bid_id:{quote_bid_id}.json
  • web-app path:/quote_bids/add_consumer_survey/quote_bid_id:${quoteId}.json
  • web-app body:total_paycommentunit
  • new API:已補 Endpoint/V1/QuoteBids.php::add_consumer_survey()
  • routing:已補 Mapping.php,支援 legacy named path。
  • 驗證狀態:staging response / DB side effect 已完成對表。
  • 正式機流量:2026-06-02 查詢 ip-10-5-2-242 access log,POST 200 有 598 筆,OPTIONS 200 有 104 筆;另有 1 筆 GET 401。

正式機 Access Log

2026-06-02 查詢機器:ip-10-5-2-242

normalized path:

筆數method / normalized pathstatus
598POST /quote_bids/add_consumer_survey/quote_bid_id:{quote_bid_id}.json200
104OPTIONS /quote_bids/add_consumer_survey/quote_bid_id:{quote_bid_id}.json200
1GET /quote_bids/add_consumer_survey/quote_bid_id:{quote_bid_id}.json401

caller 來源包含 web https://www.pro360.com.tw/、iOS consumer app Alamofire 與 Android app okhttp

Web-App 呼叫

web-app 檔案:

/Users/mattsu/Documents/Site/web-app/modules/utils/api-manager.js:827-841

APIManager.postBudgetSurvey(quoteId, budget, comment, unit)

  1. 組 path:/quote_bids/add_consumer_survey/quote_bid_id:${quoteId}.json
  2. 使用 FormData
  3. append:
    • total_pay = budget
    • comment = comment
    • unit = unit
  4. 使用 defaultPOSTConfig(data, session_token)

同區塊的讀取 API 是 getBudgetSurvey(),path 為 /quote_bids/get_consumer_survey/quote_bid_id:${quoteId}.json

Legacy Rule

legacy 檔案:

/Users/mattsu/Documents/Site/get-lancer-php56/app/Plugin/Quotes/Controller/QuoteBidsController.php:6097-6137
/Users/mattsu/Documents/Site/get-lancer-php56/app/Plugin/Quotes/Model/QuoteConsumerSurvey.php:83-109

controller 規則:

  1. 非 JSON request 或 session invalid 時,回 {"error":1,"status":"invalid request"}
  2. 從 named params 取 quote_bid_id,轉成 int。
  3. QuoteConsumerSurvey::checkQuoteBidUser(user_id, quote_bid_id)
    • bid 不存在時,回 {"error":2,"status":"quote_bid_not_found"}
    • session user 不是 request owner 時,回 {"error":3,"status":"not_consumer"}
  4. quote_bid_id 查既有 survey:
    • 沒有 row:create。
    • 已有 row:帶 existing id,覆蓋同一筆。
  5. 寫入欄位:
    • quote_request_id = quote_bids.quote_request_id
    • quote_bid_id = quote_bid_id
    • total_pay = (float)getRequestData('total_pay')
    • unit = getRequestData('unit')
    • comment = getRequestData('comment')
  6. 成功回 {"error":0,"status":"success"}

Side Effect

同步 DB:

  • insert / update quote_consumer_surveys

不做:

  • 不更新 quote_bids
  • 不更新 quote_requests
  • 不建立 quote_activities / quote_activity_consumers
  • 不寫 transaction / wallet / subscription log。
  • 不送 event queue / task event queue。
  • 不送 notification。

Schema 對照

quote_consumer_surveys 欄位:

欄位legacy 寫入new 寫入
quote_request_idquote_bids.quote_request_id同 legacy
quote_bid_idpath named param同 legacy
total_pay(float)total_pay;沒送時是 0同 legacy
unitrequest body;沒送時是 NULL同 legacy
commentrequest body;沒送時是 NULL同 legacy

new update 使用明確 SQL 覆蓋欄位,讓 unit / comment 在 request 缺值時可被寫回 NULL。若使用一般 DO modify()NULL 欄位可能不會更新,會偏離 legacy save($data)

Config 對照

這支 API 沒有讀 legacy Configure::read(...)、settings、mail / SMS / notification template、URL、icon、fee threshold 或 payment threshold。

Staging 實測

2026-06-02 staging 以同一 consumer session 實測 legacy 與 new,response 與 DB side effect 一致。

版本quote_bid_idquote_request_idrequest userresponsequote_consumer_surveys
legacy2147690474224728617{"error":0,"status":"success"}total_pay=10.00unit=單次計費comment=哈囉
new2147689089221958617{"error":0,"status":"success"}total_pay=10.00unit=單次計費comment=hello

兩筆都只新增 / 覆蓋 quote_consumer_surveysquote_request_id 取自 quote_bids.quote_request_id,且 session user 必須是 request owner。

判斷:staging response 與 quote_consumer_surveys 寫入語意已確認與 legacy 一致;這支不再列為待 staging 對表項目。

New PHP 8.2 對照

new 檔案行號對應 legacy職責狀態
Lib/Common/RouterRule/Mapping.php:161-164web-app / access log path將 legacy named path route 到 QuoteBids::add_consumer_survey()已補
Endpoint/V1/QuoteBids.php:2644-2674QuoteBidsController.php:6099-6106session guard、quote_bid_id 解析、body 解析、response mapping。已補
Lib/Model/QuoteConsumerSurvey.php:23-73QuoteBidsController.php:6108-6131查既有 survey,新增或覆蓋 quote_consumer_surveys已補
Lib/Model/QuoteConsumerSurvey.php:79-105QuoteConsumerSurvey.php:83-109legacy bid 存在與 request owner guard;保留 error 2 / 3 response。已補
tests/QuoteBidsAddConsumerSurveyTest.php:56-151success / overwrite / missing bid / non owner / invalid session覆蓋主要 DB side effect 與 guard。已補

逐段行數對照

Legacy 行號New 行號對照內容狀態
QuoteBidsController.php:6099-6103Endpoint/V1/QuoteBids.php:2647-2654session guard;invalid session 回 error=1/status=invalid request已對齊
QuoteBidsController.php:6105-6110Endpoint/V1/QuoteBids.php:2657-2667, QuoteConsumerSurvey.php:79-105named quote_bid_id 與 request owner guard。已對齊
QuoteBidsController.php:6112-6121QuoteConsumerSurvey.php:27-44quote_bid_id 查 existing survey;存在就覆蓋。已對齊
QuoteBidsController.php:6123-6128QuoteConsumerSurvey.php:45-64quote_request_idquote_bid_idtotal_payunitcomment已對齊
QuoteBidsController.php:6130-6133Endpoint/V1/QuoteBids.php:2669成功 response error=0/status=success已對齊

測試

docker exec -w /project-data cd63f9147e8d vendor/bin/phpunit tests/QuoteBidsAddConsumerSurveyTest.php

結果:

OK (5 tests, 24 assertions)

測試覆蓋:

  • request owner 新增 survey。
  • 同一 quote_bid_id 重複呼叫會覆蓋同一筆 survey。
  • body 缺 total_pay / unit / comment 時,total_pay=0.00unit/comment=NULL
  • bid 不存在回 error=2/status=quote_bid_not_found
  • 非 request owner 回 error=3/status=not_consumer
  • invalid session 回 error=1/status=invalid request