ForgeFlow-ERP/docs/superpowers/plans/2026-06-02-semi-finished-measure-basis.md
2026-06-14 21:05:49 +08:00

108 lines
4.6 KiB
Markdown

# 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.