適用範圍:POSTING_DATA、POSTED_TO_OFFICE_DATA、POSTED_TO_ADDR_DATA,即「任官」主檔、職官資料與職官地址對應。
- 一律經由 Repository,方法使用資料庫交易 (
DB::transaction). - 主要步驟:
- 取出新 posting id:
POSTING_DATA使用lockForUpdate()取得目前最大值並加一。 - 寫入
POSTING_DATA,確認c_personid與c_posting_id建檔。 - 呼叫
insertAddr($c_addr, $personId, $postingId, $officeId)重建地址清單。傳入陣列內若含-999代表「未填」,會存成c_addr_id = 0;若陣列為空,最後POSTED_TO_ADDR_DATA會沒有紀錄。 - 呼叫
ToolsRepository::timestamp($data, true)產生c_created_by/c_created_date/c_modified_by/c_modified_date。 - 寫入
POSTED_TO_OFFICE_DATA。 - 以
OperationRepository::store(..., op_type=1, resource='POSTED_TO_OFFICE_DATA')建立操作紀錄,resource_id為{c_office_id}-{c_posting_id}。
- 取出新 posting id:
- 交易化:整個更新(主表 + 地址)包在單一 transaction 中。
- 入口會把 request 拆成:原始職官資料 (
$ori)、新資料 ($data)、地址陣列 ($incomingAddr)。 - 判斷變動:
$hasPostingChange = hasMeaningfulChanges($data, $ori, ['c_modified_by', 'c_modified_date']);$hasAddressChange會比較$incomingAddr與既有地址清單(selectionListHasChanges,-999視為 0)。
- 更新邏輯:
- 若職官欄位有變動,才會呼叫
timestamp()並更新POSTED_TO_OFFICE_DATA,然後寫op_type = 3的 operation snapshot。只動地址時不會改主表 timestamp,以避免在測試場景(無登入使用者)碰到Auth::user()->name例外。 - 若地址有變動或
c_office_id改變,會:- 讀取舊地址集合作為
beforeRows; - 如
c_office_id改變且舊資料存在,先清掉舊的POSTED_TO_ADDR_DATA; - 重建地址資料:使用新的陣列(
$incomingAddr)或沿用舊列表。 - 取得重新寫入後的地址資料 (
afterRows),並以OperationRepository::store(..., resource='POSTED_TO_ADDR_DATA')存成rowsJSON。
- 讀取舊地址集合作為
- 回傳
{ 'id' => '{officeId}-{postingId}', 'no_changes' => false }或{..., 'no_changes' => true }。
- 若職官欄位有變動,才會呼叫
- 交易化處理。傳入
id格式{officeId}-{postingId}。 - 步驟:
- 讀取對應
POSTED_TO_OFFICE_DATA紀錄作為 operation 快照。 - 刪除
POSTED_TO_OFFICE_DATA。 - 刪除
POSTED_TO_ADDR_DATA中所有同c_posting_id(不限定 office 或 person)。 - 刪除
POSTING_DATA主檔。 - 寫入
op_type = 4的刪除操作紀錄,資源POSTED_TO_OFFICE_DATA。
- 讀取對應
- 先刪除該 posting+office 既有地址,再用傳入陣列寫回。
-999代表「無地址」,存入時換成 0。- 建立與更新都會調用。
- 刪除任官時不會呼叫此方法,改由 transaction 直接清空對應 posting。
resource欄位分別:POSTED_TO_OFFICE_DATA、POSTED_TO_ADDR_DATA、POSTING_DATA。resource_id統一採{c_office_id}-{c_posting_id}。- 地址變動的
resource_data以rows包含 before/after 清單(每列含c_personid,c_posting_id,c_office_id,c_addr_id)。 - 刪除任官後會寫入整筆
POSTED_TO_OFFICE_DATA的 JSON 快照,但地址是以 posting id chained 的POSTED_TO_ADDR_DATA收集。
- Feature 測試需
actingAs()讓ToolsRepository::timestamp()能取得登入者姓名。 - 若只測地址更新,請確認 Operations 會寫入
POSTED_TO_ADDR_DATA的 before/after JSON,而POSTED_TO_OFFICE_DATA不會誤觸。 - 刪除流程確認
POSTED_TO_ADDR_DATA與POSTING_DATA一併清空。 - 常用測試:
tests/Feature/OfficePostingStoreTest.phptests/Feature/OfficeAddressOperationLoggingTest.php
- UI 表單的 address multi-select 會在送出時將 "未選" 表示為
-999;POSTING repository 會自動轉換為c_addr_id = 0。 - 若之後需要支援「某官職無地址欄位」,記得前端送出空陣列即可,Repository 會維持無資料狀態。
- Restore 功能目前對任官類型仍停用;operations snapshot 主要作為稽核依據。
- 方法命名沿用歷史:
officeStoreById/officeUpdateById/officeDeleteById實際處理的是整個 posting 及其地址與相關資料,若未來要重構可考慮改成posting*類型名稱,但現階段先維持現狀以免破壞既有呼叫點。