QuoteServices Change Status Profile Ready

API:

POST /quote_services/change_status/profile_ready/{quote_service_id}.json

功能說明

provider 完成 onboarding 服務資料後呼叫。這支會把 service 設為可接案狀態,並依 start_identity_free_credit_user_id 判斷是否進舊版免費點數流程。

成功 response:

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

快速結論

  • 呼叫者:service owner,需有效 REST API key 與 user session token。
  • legacy API:QuoteServicesController::change_status('profile_ready', $quote_service_id)
  • new API:已補 Endpoint/V1/QuoteServices.php::change_status_profile_ready()
  • routing:已補 /quote_services/change_status/profile_ready/{quote_service_id}.json
  • DB 寫入:
    • quote_services.is_active = 1
    • quote_services.is_archived = 0
    • 更新 quote_services.modified
    • users.onboard_state = 2
    • 新增 quote_activitiesquote_activity_type_id = 34 (ServiceProfileReady)
  • 舊版免費點數分支仍保留:
    • 可能新增 task_queue.action = newQuoteService
    • 可能新增 transactions.class = FreeCreditEvent
    • 可能新增 wallet_balance_logs
    • 可能新增 user_internal_logs
    • 可能新增 event_queue.event_key = Pro_Ready

目前本機 start_identity_free_credit_user_id = 1。常用測試 user 8616 只會啟用 service、設定 onboard;不發免費點數、不排 newQuoteService、不送 Pro_Ready

前端呼叫鏈:

/dashboard/onboarding/{quote_service_id}
-> OnboardingContainer.nextStep() description step
-> OnboardingContainer.onEndOnboarding()
-> APIManager.markServiceProfileReady()
-> POST /quote_services/change_status/profile_ready/{quote_service_id}.json

Staging 手動觸發方式

若 provider 已經完成 onboarding,但要在 staging 重新觸發這支 API,最小 DB 準備是把 service owner 的 users.onboard_state 暫時改回未完成狀態,再用該 owner session 操作 onboarding 或直接呼叫 API。

先查 owner:

SELECT qs.id AS quote_service_id, qs.user_id, u.onboard_state
FROM quote_services qs
JOIN users u ON u.id = qs.user_id
WHERE qs.id = {quote_service_id};

staging / test 才可暫時調整:

UPDATE users SET onboard_state = 1 WHERE id = {owner_user_id};

呼叫成功後預期 users.onboard_state = 2。不要直接改 service owner;API 有 owner guard,必須使用該 service owner 的 session token。

Legacy Rule

legacy controller:

/Users/mattsu/Documents/Site/get-lancer-php56/app/Plugin/Quotes/Controller/QuoteServicesController.php
legacy 行號職責
3452-3467change_status($filter, $quote_service_id) 入口;JSON request 且 session 有效時,加上 QuoteService.user_id = current user owner guard。
3468-3471預設 response:{"error":1,"status":"Invalid request"}
3497-3499profile_ready 分支呼叫 _handle_profile_ready(),activity type 設為 ServiceProfileReady
3501-3508type 有效時 save、回 {"error":0,"status":"Success"},並建立 quote service activity。
3989-3999_handle_profile_ready() 以 Redis key _handle_profile_ready_{user_id} 做 60 秒防重;重複呼叫只記 log 後 return。外層仍回 success 並寫 activity。
4003-4010設定 quote_services.is_active = 1is_archived = 0
4012-4020user_id > start_identity_free_credit_user_id,只更新 users.onboard_state = 2 後 return。
4024-4037若已領過免費點數,或 wallet balance > 0,只更新 users.onboard_state = 2
4038-4046未領過且 wallet 為 0 時,排 TaskQueue.newQuoteService,取得 quote.free_credit_new_provider 免費點數設定。
4048-4068一次性 email domain 不符合資格:free_credit = 0,寫 user_internal_logs
4070-4088IP 黑名單不符合資格:free_credit = 0,寫 user_internal_logs
4091-4122users.phone,檢查相同電話;不符合資格時 free_credit = 0、寫 user_internal_logsfree_auto_quote = 0
4125-4155free_credit > 0 時 lock user、加 wallet、onboard_state = 2、寫 free credit transaction 與 wallet balance log;exception 只記 log。
4156-4163free_credit <= 0 時只更新 users.onboard_state = 2
4166呼叫 sendProviderReadyToQuoteMail()

legacy provider ready notification:

/Users/mattsu/Documents/Site/get-lancer-php56/app/Plugin/Quotes/Model/QuoteService.php
legacy 行號職責
4931-4964建立 Pro_Ready event payload 基本欄位:user_idquote_service_id
4966-4971legacy email task 220 Ready To Quote Notification 已註解,不會進 event queue。
4973-4988free_credit > 0 時加入 MoEngage Receive_Free_Credit task。
4991-4993寫入 event_queue.event_key = Pro_Ready

New PHP 8.2 對照

new 檔案行號對應 legacy職責
Lib/Common/RouterRule/Mapping.php:53-56access log 實際 pathroute 到 QuoteServices::change_status_profile_ready()
Endpoint/V1/QuoteServices.php:135-152QuoteServicesController.php:3452-3499session/API guard、path id、owner guard、invalid request response。
Endpoint/V1/QuoteServices.php:153-1573501-3504, 3989-4173呼叫 QuoteService::handleProfileReady() 處理寫入與通知;再更新 quote_services.modified,對齊 legacy 外層 save($_data)
Endpoint/V1/QuoteServices.php:159-1713505-3508建立 ServiceProfileReady activity,回 success response。
Lib/Model/QuoteService.php:94-1043989-3999Redis 防重;重複呼叫時 helper return,endpoint 仍會回 success 並寫 activity。
Lib/Model/QuoteService.php:106-1174003-4020啟用 service、取消封存;超過 start_identity_free_credit_user_id 時只設 onboard 後 return。
Lib/Model/QuoteService.php:119-128, Transaction.php:202-2134024-4037判斷已領免費點數或 wallet balance > 0;符合時只設 onboard。
Lib/Model/QuoteService.php:130-1374038-4046newQuoteService,讀 free_credit_events,缺 DB event 時 fallback ProConfig::get('quote.free_credit_new_provider')
Lib/Model/QuoteService.php:139-168, 337-3444048-4088email domain / IP 資格檢查,寫 user_internal_logs
Lib/Model/QuoteService.php:170-181, 252-2934091-4122補 phone、檢查相同電話、必要時關 free_auto_quote
Lib/Model/QuoteService.php:184-230, FreeCreditEvent.php:21-334125-4163free credit wallet transaction、transactionswallet_balance_logs、onboard fallback。
Lib/Model/QuoteService.php:296-3344931-4993Pro_Ready event;free_credit > 0 時加入 Receive_Free_Credit MoEngage task。MoEngage first_name 照 legacy 使用 last_name . first_name

Config / DB 設定檢查

切 staging / production 前要確認實際部署環境,不可只看本地 legacy checkout:

key / table用途new 讀取位置備註
start_identity_free_credit_user_id決定是否跳過舊版 profile ready 免費點數流程ConstantUtil::get('start_identity_free_credit_user_id')user id 大於此值時只設 onboard,不排 queue / event。
free_credit_events.slug = quote.free_credit_new_provider免費點數金額與 event idFreeCreditEvent::getEventBySlug(..., true)優先使用 DB event。
quote.free_credit_new_providerDB event 不存在時的免費點數 fallbackProConfig::get('quote.free_credit_new_provider')本機 Configuration.php 目前未見此 key;部署環境需確認。

legacy sendProviderReadyToQuoteMail() 會建立但不送出的 email replace content 讀到:

site.language
site.url
credit.info.url
email.signature
mail.icon.vendor_tips

因 legacy email task 已註解,new 目前不讀這些 key;若日後恢復 220 Ready To Quote Notification email task,需同步補齊並驗證這些 config。

測試

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

結果:

OK (2 tests, 22 assertions)

測試覆蓋:

  • owner 可將自己的 service 標記 profile ready。
  • 在目前 start_identity_free_credit_user_id = 1 分支下,成功後 is_active = 1is_archived = 0、更新 quote_services.modifiedusers.onboard_state = 2
  • 成功後建立 ServiceProfileReady activity。
  • 此分支不新增 newQuoteService task、Pro_Ready event、free credit transaction、wallet balance log。
  • 非 owner 回 legacy invalid request,不寫 DB / queue / event。

測試會快照並還原 user 8616 的 wallet / onboard / phone 等欄位,避免污染共用測試使用者。

Staging 實測

2026-06-05 以 legacy staging 驗證:

POST /quote_services/change_status/profile_ready/9930.json

response:

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

DB 結果:

  • quote_services.id = 9930user_id = 8617is_active = 1is_archived = 0modified = 2026-06-05 07:24:25
  • users.id = 8617onboard_state = 2available_wallet_amount = 4441
  • 新增 quote_activities.id = 406809quote_activity_type_id = 34model = QuoteServiceforeign_id = 9930
  • 未新增 task_queue.action = newQuoteService
  • 未新增 event_queue.event_key = Pro_Ready
  • 未新增 transactions.class = FreeCreditEvent;最近 wallet log 仍停在 2026-06-01,這次呼叫沒有改 wallet。