|
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485 |
- # Deploy note — PO line m18Id rematch (recode)
- Date: 2026-08-19
- Branch / build: uncommitted (QA before prod)
- Author: agent + QA
-
- ## Summary
- - PO/DO sync failed when M18 recoded a product (`proId` changed, item **code** unchanged), e.g. `PFP002PO26080303` lines `20022` / `20023` / `20024`.
- - Sync now **links** the new M18 id onto the existing local item (same **code + type**) and **does not** rebuild/delete `item_uom`.
-
- ## Scope
- - Backend: `ItemsService.saveItem`, `M18MasterDataService.saveProduct` / `saveProducts`, remap helper
- - Frontend: none
- - DB / Liquibase: none
- - Config / ops: none (use existing `GET /m18/test/po-by-code`)
-
- ## Commits
- - (not committed yet)
-
- ## Safety rules (what this deploy will / will not do)
-
- | Situation | Behaviour |
- |-----------|-----------|
- | Local item already has that `m18Id` | Unchanged: normal product/PO update |
- | Same **code + type**, new unused `m18Id` | Update `items.m18Id` only. **No** UOM delete/rebuild, **no** QC/name wipe |
- | New `m18Id` already on **another** item | Refuse (keep old mapping) |
- | Same code, **different** type | Will **not** auto-link (same as before for type mismatch) |
- | Brand-new M18 product, no local code | Creates item + UOMs as before |
- | Scheduled product sync of already-mapped items | Unchanged full product/UOM sync |
- | Local PO status not `PENDING` | PO resync is **skipped** (existing rule) |
-
- ## Pre-check SQL (prod or staging, before resync)
-
- ```sql
- -- 1) Failed PO lines for this PO
- SELECT d.id, d.m18Id AS m18_line_id, d.status, d.dataLog, d.createDate
- FROM m18_data_log d
- WHERE d.refType = 'Purchase Order Line'
- AND d.status = 'FAIL'
- AND d.dataLog LIKE '%PFP002PO26080303%'
- ORDER BY d.id DESC
- LIMIT 20;
-
- -- 2) Local PO must be PENDING
- SELECT id, code, status, m18Id
- FROM purchase_order
- WHERE code = 'PFP002PO26080303' AND deleted = 0;
-
- -- 3) After you know the 3 M18 product codes, confirm one local row each
- SELECT id, code, name, type, m18Id
- FROM items
- WHERE deleted = 0 AND code IN ('CODE1', 'CODE2', 'CODE3');
- ```
-
- Confirm each of the three codes has **exactly one** local row, and its current `m18Id` is **not** already `20022`/`20023`/`20024` on a *different* item:
-
- ```sql
- SELECT id, code, m18Id FROM items
- WHERE deleted = 0 AND m18Id IN (20022, 20023, 20024);
- ```
-
- Expected before fix: **no rows** (or only unrelated items — if any, **do not** auto-resync; fix mapping manually).
-
- ## Test plan
-
- | # | Steps (who / where / data) | Expected result |
- |---|----|-----|
- | 1 | **Staging first.** Snapshot `items.m18Id` + `item_uom` counts for the 3 item codes. | Baseline recorded |
- | 2 | Confirm M18 products `20022`/`20023`/`20024` still have the **same codes** as local items. | Codes match; types still map to the same FPSMS `type` |
- | 3 | Confirm local PO `PFP002PO26080303` status is **PENDING**. | If not pending, stop — resync will skip the whole PO |
- | 4 | Call `GET /m18/test/po-by-code?code=PFP002PO26080303` (auth as ops). | HTTP 200; `totalFail` for those 3 lines is 0 (or success list includes the PO) |
- | 5 | SQL: `items.m18Id` for the 3 codes is now 20022/20023/20024. `item_uom` **row count and ids unchanged**. QC category / shelf life unchanged. | Remap-only; no UOM wipe |
- | 6 | UI: PO workbench / PO detail for `PFP002PO26080303` shows **6 lines** (previously 3 missing). | Failed lines created |
- | 7 | **Regression:** pick a normal mapped item, run scheduled or `GET /m18/product/{existingM18Id}`. | Item still updates as before; UOMs still sync |
- | 8 | Confirm no new `PO_LINE FAIL` email for this PO after resync. | Alert not re-sent for these 3 proIds |
-
- ## Out of scope / not tested
- - Recoded products whose **item code also changed** (will not auto-link)
- - Non-`PENDING` PO overwrite (by design skipped)
- - DO with the same recode (same `resolveLocalItemId` path; spot-check only if a DO uses these 3 items)
- - Live M18 UOM id change on the recoded product (PO qty conversion still uses existing purchase UOM)
-
- ## Rollback
- - Revert backend deploy (no Liquibase, no frontend).
- - If only `items.m18Id` was updated, restore previous `m18Id` from the pre-check snapshot. PO lines already inserted stay; delete/fix only if QA rejects the PO.
- - Do **not** run a full product resync on the new proIds expecting to undo UOMs — this path does not rewrite UOMs.
|