# Semi-Finished Measure Basis Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Make semi-finished inventory use one locked measure basis per semi-finished item-operation in a warehouse: by piece or by weight. **Architecture:** Do not add a database column unless tests prove derivation is insufficient. Derive the measure basis from semi-finished stock lots: `remaining_qty/inbound_qty` means by piece, `remaining_weight_kg/inbound_weight_kg` means by weight, both means legacy mixed. Backend enforces exactly one inbound basis and blocks mismatched new inbound for existing semi-finished stock; frontend presents only the correct input and availability wording. **Tech Stack:** FastAPI, SQLAlchemy, pytest, Vue 3, Vite, Node assertion script. --- ### Task 1: Backend Measure Basis Enforcement **Files:** - Modify: `backend/app/api/routes/inventory.py` - Modify: `backend/tests/test_semi_finished_operation_inventory.py` - [ ] **Step 1: Write failing backend tests** Add tests that prove: - semi-finished inbound rejects filling both quantity and weight; - semi-finished inbound rejects filling neither quantity nor weight; - once a semi-finished item-operation has by-piece stock, later by-weight inbound is rejected; - once a semi-finished item-operation has by-weight stock, later by-piece inbound is rejected. - [ ] **Step 2: Run red tests** Run: `.venv/bin/python -m pytest tests/test_semi_finished_operation_inventory.py -q` Expected before implementation: at least the mismatch/both-filled tests fail because current backend accepts both fields and does not enforce existing basis. - [ ] **Step 3: Implement minimal backend helper** Add helper logic in `create_warehouse_inbound`: - determine requested basis: `PIECE` when `inbound_qty > 0 and inbound_weight == 0`, `WEIGHT` when `inbound_weight > 0 and inbound_qty == 0`; - reject both-filled and neither-filled for `WIP_IN` / `OUTSOURCING_IN`; - query existing semi-finished lots for same `item_id`, `warehouse_id`, `source_line_id` with remaining quantity or weight; - derive existing basis; if it is `MIXED`, reject with a Chinese message asking to clean historical stock first; - if existing basis exists and differs from requested basis, reject with a Chinese message that the semi-finished item must follow existing measure basis. - [ ] **Step 4: Run backend tests** Run: `.venv/bin/python -m pytest tests/test_semi_finished_operation_inventory.py -q` Expected: all semi-finished tests pass. ### Task 2: Frontend Semi-Finished UI Basis **Files:** - Modify: `frontend/src/views/InventoryLedgerView.vue` - Modify: `frontend/src/utils/inventoryOperationOptions.js` - Modify: `frontend/scripts/test-inventory-ledger-options.mjs` - [ ] **Step 1: Write/update frontend assertions** Assert the source contains: - user-facing label `半成品` instead of semi warehouse `产品工序`; - `入库类型`, `按件入库`, `按重入库`; - helper logic that formats semi availability by basis instead of always `formatWeight(...)`; - payload sends only `inbound_qty` for piece basis and only `inbound_weight_kg` for weight basis. - [ ] **Step 2: Run red frontend assertion** Run: `node scripts/test-inventory-ledger-options.mjs` Expected before implementation: fails on missing measure-basis UI or payload logic. - [ ] **Step 3: Implement frontend UI** In `InventoryLedgerView.vue`: - rename semi item field labels from `产品工序` to `半成品`; - add `genericForm.measure_basis`; - when semi inbound item changes, derive existing basis from `semiFinishedBalances` and auto-fill/lock `measure_basis`; - show only `入库数量` for `PIECE`, only `入库重量(kg)` for `WEIGHT`; - for semi outbound, derive basis from selected semi option and show only the matching outbound input; - display `-` for irrelevant quantity/weight values in semi balances and lots. In `inventoryOperationOptions.js`: - carry `measure_basis` through semi outbound options. - [ ] **Step 4: Run frontend checks** Run: `node scripts/test-inventory-ledger-options.mjs` Expected: assertion script passes. Run: `npm run build` Expected: Vite build completes successfully. ### Task 3: Final Verification **Files:** - Verify only. - [ ] **Step 1: Run backend full test suite** Run: `.venv/bin/python -m pytest tests -q` Expected: all backend tests pass. - [ ] **Step 2: Browser smoke** Run frontend dev server and open `http://127.0.0.1:5173/` in the in-app browser. Expected: page loads with title `百华智能五金 ERP` and no console errors.