# 电表箱成品装配 · 端到端业务回归测试链路 > 本文档是**一条从头走到尾、环环相扣、不许断、禁止分支**的完整回归测试链路。 > 以「装配 1 台成品电表箱」为主线,从物料还没进公司门开始,一路走到成品入库、多余料退回库房、成品可追溯。 > 每一步的**前置数据都由它前面的步骤产出**;每一步都给出**具体数值的断言**(表名·字段·期望值·数量等式)。 > 全链路只有一条路径,没有"如果…就…"、没有"否则"、没有"另一种情况"。 > > 涉及三个系统:库房系统(WMS,端口 8890,接口前缀 `/api`)、产线系统(MES,端口 8888,接口前缀 `/api/v1`)、工位终端(端口 8892,接口前缀 `/api`)。 > 系统之间内部互调用 `X-API-TOKEN` 头保护(值 `Hardman_2026`)。 > 登录态用 JWT:库房/工位终端登录后带 `Authorization: Bearer `;产线系统同理。 --- ## 一、链路总览(一条主线) ``` 【主数据准备】 建产品型号(电表箱) → 建物料档案(铁架子/门子/电气件/螺丝/成品) → 建库区(A区) → 建产品物料清单BOM(4种料, 各归属装配工序) → 建工艺流程(3个流程绑工位2/5·6/8) → 工位派工(工位2=工序1, 工位5=工序2, 工位6=工序2, 工位8=工序3) 【物料进厂:入库 → 检验】 结构件按批次入库(铁架子/门子/螺丝, 质量状态=未检) → 电气件按序列号SN入库(4颗, 质量状态=未检) → 来料检验(逐批/逐SN判合格 → 库存质量状态改「合格」) 【工单与排产】 建工单(电表箱, 数量1, 状态=已创建) → 日排产(生产日D, 计划1台, 状态=待执行) → 工单下发(已创建→已下发) → 工单开工(已下发→执行中, 联动排产 待执行→执行中) 【备料与出库(生产日D早上)】 生成备料单(按排产+派工算料, 同步工单物料台账, 立即自动出库只领「合格」品) → 库存扣减(铁架子-1/门子-1/电气件SN×2/螺丝-3), 台账累计出库达标置「领料完结」 → 接料确认(4张备料单 已接料=已发出, 状态置「已完结」) 【上线装配:3道工序顺序流转】 工件上线(SN=WP-DX-0001, 状态=已上线, 当前工序=0) → 报工工序1(工位2, 绑铁架子批次+门子批次 → 当前工序=1) → 报工工序2(工位5, 绑2颗电气件SN → 当前工序=2) 〔工位6是同工序并行位〕 → 拧紧上报(工位8, 拧2颗螺丝, 写2条拧紧记录+扭矩判定) → 报工工序3(工位8, 绑螺丝批次 → 当前工序=3) 【完工与成品入库】 完工(兜底校验3工序物料齐套 → 工件状态=已完工, 建关联追溯, 工单已完工数+1, 排产已完成数+1置「已完成」, 成品回流库房库存(成品SN=工件SN, 品类=成品, 数量1, 合格, 在库), 反冲核销台账已消耗量〔只核销台账, 不再动库存, 库存已在出库时扣过〕) → 工单完工流转(执行中→已完成) 【多余料回仓库 + 追溯】 工位退料(工位8, 螺丝用剩1颗 → 库房预建待确认退库单) → 库管确认收货(退库单置「已收货」, 螺丝加回 1 颗置「未检」, 在库总量 97→98) → 成品追溯(按成品SN回查: 工序时间线/操作人/物料批次SN/拧紧数据 全链路可追) ``` **贯穿全链路的 1 台成品**:成品序列号 `WP-DX-0001`,工单 `WO-20260922-001`,产品 `DX-100 电表箱`。 --- ## 二、示例数据基线(全链路统一口径) ### 2.1 产品与物料 | 编码 | 名称 | 品类 | 管理方式 | 说明 | |---|---|---|---|---| | DX-100 | 电表箱 | 成品 | 序列号(2) | 本链路装配的成品 | | TLJ-01 | 铁架子 | 原材料 | 结构件·批次(1) | 工序1装配,单台用量1 | | MEN-01 | 门子 | 原材料 | 结构件·批次(1) | 工序1装配,单台用量1 | | DQJ-01 | 电气件 | 原材料 | 电气件·序列号(2) | 工序2装配,单台用量2 | | LS-01 | 螺丝 | 原材料 | 结构件·批次(1) | 工序3装配,单台用量2,损耗率50% | ### 2.2 产品物料清单(BOM,产品 DX-100,清单名「默认」) | 物料 | 管理方式 | 单台用量 | 损耗率 | 装配工序 | |---|---|---|---|---| | TLJ-01 铁架子 | 结构件(1) | 1 | 0% | 工序1 | | MEN-01 门子 | 结构件(1) | 1 | 0% | 工序1 | | DQJ-01 电气件 | 电气件(2) | 2 | 0% | 工序2 | | LS-01 螺丝 | 结构件(1) | 2 | 50% | 工序3 | > 螺丝损耗率 50% 的含义:按「试拧/滑牙预留」,单台标准备料 = 2 ×(1+50%) = 3 颗;实际装配拧 2 颗,剩 1 颗完工后退回库房。这是"多余的料回仓库"的数据来源。 ### 2.3 工位派工(生产日 D,班次=单班) | 工位号 | 工序编号 | 承担装配 | |---|---|---| | 2 | 工序1 | 装铁架子 + 门子 | | 5 | 工序2 | 装电气件(本工件走此工位) | | 6 | 工序2 | 装电气件(同工序并行位,本工件不经过) | | 8 | 工序3 | 拧螺丝 | > 连续性校验:按工位号升序,工序编号为 `1,2,2,3`,单调不降、不穿插,合法。 ### 2.4 工艺流程(每个工位绑定一个启用流程) | 流程名 | 绑定工位 | 工序步骤 | |---|---|---| | 装铁架子门子 | 工位2 | 步骤「装铁架子」、步骤「装门子」 | | 装电气件 | 工位5、工位6 | 步骤「装电气件」 | | 拧螺丝 | 工位8 | 步骤「拧螺丝1」(扭矩采集,标准:扭矩 RANGE 8~12)、步骤「拧螺丝2」(扭矩采集,标准:扭矩 RANGE 8~12) | > 工位8 的流程含 **2 个扭矩采集步骤**,所以拧紧汇总里「应拧颗数=2」;实拧 2 颗即满足。 ### 2.5 工单 / 排产 / 批次 / 序列号 - 工单号 `WO-20260922-001`,产品 DX-100,数量 **1** 台。 - 生产日 **D = 2026-09-22**(`生成备料单` 取"系统当天"作为派工生效日,因此**派工生效日 = 排产日 = 备料日 = D = 执行回归测试的当天**;入库/建单可在 D-1=2026-09-21 完成)。 - 入库批次 / 序列号: - 铁架子批次 `PC-TLJ-001`,入库 **5** 个 - 门子批次 `PC-MEN-001`,入库 **5** 个 - 螺丝批次 `PC-LS-001`,入库 **100** 颗 - 电气件序列号 `SN-DQ-001`、`SN-DQ-002`、`SN-DQ-003`、`SN-DQ-004`,各 1 颗(共 **4** 颗) - 成品序列号(=工件序列号):`WP-DX-0001` ### 2.6 数量主线(最终必须闭合的等式,逐步在下方断言) | 物料 | 入库 | 出库到工位 | 退回库房 | 期末在库 | 装进成品 | |---|---|---|---|---|---| | 铁架子 TLJ-01 | 5 | 1 | 0 | 4 | 1 | | 门子 MEN-01 | 5 | 1 | 0 | 4 | 1 | | 电气件 DQJ-01 | 4(SN) | 2(SN001,002) | 0 | 2(SN003,004) | 2 | | 螺丝 LS-01 | 100 | 3 | 1 | 98 | 2 | | 成品 DX-100 | — | — | — | 1(WP-DX-0001) | — | --- ## 三、端到端步骤 > 每一步统一格式: > - **前置**:本步开始前必须已存在的数据(且都来自前面步骤)。 > - **操作**:角色 + 系统 + 菜单 + 接口 + 请求体关键字段。 > - **系统反应**:业务语言描述系统做了什么。 > - **数据变化**:哪张表、哪个字段、变成什么值。 > - **断言**:具体数值 / 状态 / 条数 / 等式。 ### 阶段一 · 主数据准备 --- ## Step 1:建产品型号(电表箱) **前置**:无(链路起点)。产线系统已登录(账号具备"产品型号"维护权限)。 **操作**:工艺员在【产线系统 → 基础数据 → 产品型号】点"新增",填:名称=电表箱、编码=DX-100、规格型号=DX-100 户用单相、单位=台、类别=成品、启用=是。 - 接口:`POST /api/v1/product-types` - 请求体:`{"name":"电表箱","code":"DX-100","spec":"DX-100 户用单相","unit":"台","category":"成品","isActive":true}` **系统反应**:新增一条产品型号并启用。 **数据变化**:产品型号表新增一行:编码=DX-100、名称=电表箱、规格=DX-100 户用单相、单位=台、类别=成品、启用=是。 **断言**: - `GET /api/v1/product-types?code=DX-100` 返回 1 条,名称=电表箱、启用=是。 - 记下返回的产品型号主键 id(记作 `${productTypeId}`),Step 10 建工单要用。 --- ## Step 2:建物料档案(5 个物料) **前置**:Step 1 完成(成品 DX-100 也在此建档,供成品入库带出名称)。库房系统已登录(账号具备"物料档案:新增"权限)。 **操作**:仓管在【库房系统 → 基础数据 → 物料档案】逐个"新增"。 - 接口:`POST /api/material/create` - 5 次请求体(除说明外全部必填:图号/名称/规格/单位/品类/类型): | # | 请求体 | |---|---| | 铁架子 | `{"code":"TLJ-01","name":"铁架子","spec":"TLJ-01","unit":"个","itemType":1,"manageMode":1,"safetyStock":10}` | | 门子 | `{"code":"MEN-01","name":"门子","spec":"MEN-01","unit":"个","itemType":1,"manageMode":1,"safetyStock":10}` | | 电气件 | `{"code":"DQJ-01","name":"电气件","spec":"DQJ-01","unit":"个","itemType":1,"manageMode":2,"safetyStock":10}` | | 螺丝 | `{"code":"LS-01","name":"螺丝","spec":"M4×10","unit":"颗","itemType":1,"manageMode":1,"safetyStock":50}` | | 成品 | `{"code":"DX-100","name":"电表箱","spec":"DX-100 户用单相","unit":"台","itemType":3,"manageMode":2,"safetyStock":0}` | **系统反应**:新增 5 条物料档案;结构件按批次管理、电气件按序列号管理自动置位;图号唯一校验通过。 **数据变化**:物料表新增 5 行。以铁架子为例:图号=TLJ-01、名称=铁架子、管理方式=1、按批次管理=是、按序列号管理=否、品类=1(原材料)、安全库存=10。电气件 DQJ-01:管理方式=2、按序列号管理=是。成品 DX-100:品类=3(成品)、管理方式=2。 **断言**: - `GET /api/material/query?code=TLJ-01` 等逐个返回 1 条,管理方式与上表一致。 - 铁架子/门子/螺丝 管理方式=1;电气件/成品 管理方式=2。 - 重复提交同一图号返回冲突提示"图号已存在"。 --- ## Step 3:建仓库区域(A 区) **前置**:Step 2 完成。库房系统已登录(账号具备"区域:新增"权限)。 **操作**:仓管在【库房系统 → 库位管理 → 区域】新增一级区域。 - 接口:`POST /api/zone/node/create` - 请求体:`{"level":1,"code":"A","name":"合格品存储区"}` **系统反应**:新增一级区域,区域编码自动转大写为 A。 **数据变化**:区域表新增一行:层级=1、编码=A、区域编码=A、名称=合格品存储区。 **断言**: - `GET /api/zone/list` 含层级=1、区域编码=A 的记录。 - Step 7/8 入库时 `zoneCode=A` 必须能命中此区域。 --- ## Step 4:建产品物料清单(BOM) **前置**:Step 1(产品 DX-100)、Step 2(4 种零部件物料档案已存在)。产线系统已登录。 **操作**:工艺员在【产线系统 → 基础数据 → 产品物料清单】为 DX-100 维护清单(清单名「默认」),录入 4 行物料并指定各自装配工序。 - 接口:`PUT /api/v1/bom` - 请求体(关键:每行的 `manageMode` 管理方式、`unitQty` 单台用量、`lossRate` 损耗率、`processCode` 装配工序): ```json { "productCode": "DX-100", "bomName": "默认", "items": [ {"materialCode":"TLJ-01","materialName":"铁架子","unit":"个","manageMode":"1","unitQty":1,"lossRate":0,"processCode":1}, {"materialCode":"MEN-01","materialName":"门子","unit":"个","manageMode":"1","unitQty":1,"lossRate":0,"processCode":1}, {"materialCode":"DQJ-01","materialName":"电气件","unit":"个","manageMode":"2","unitQty":2,"lossRate":0,"processCode":2}, {"materialCode":"LS-01","materialName":"螺丝","unit":"颗","manageMode":"1","unitQty":2,"lossRate":50,"processCode":3} ] } ``` **系统反应**:按「产品编码+清单名+物料编码」覆盖式保存 4 行物料清单。 **数据变化**:物料清单表新增 4 行,产品编码=DX-100、清单名=默认。铁架子行:装配工序=1、单台用量=1、损耗率=0。电气件行:装配工序=2、单台用量=2、管理方式=2。螺丝行:装配工序=3、单台用量=2、损耗率=50。 **断言**: - `GET /api/v1/bom?productCode=DX-100&bomName=默认` 返回 **4** 行。 - 各行的 装配工序 / 单台用量 / 损耗率 / 管理方式 与请求体一致。 - 工序分布:工序1 有 2 种料(铁架子、门子)、工序2 有 1 种料(电气件)、工序3 有 1 种料(螺丝)。 --- ## Step 5:建工艺流程(3 个流程,绑定工位 2/5·6/8) **前置**:工位 2、5、6、8 为系统内置工位(种子数据已存在)。产线系统已登录。 **操作**:工艺员在【产线系统 → 工艺管理 → 工艺流程】新建 3 个启用流程,并绑定工位、维护工序步骤。 - 接口:`POST /api/v1/process-flows` - 流程1(装铁架子门子,绑工位2): ```json {"name":"装铁架子门子","status":"ACTIVE","stations":[2], "steps":[{"seq":1,"name":"装铁架子","collectType":"手动"},{"seq":2,"name":"装门子","collectType":"手动"}]} ``` - 流程2(装电气件,绑工位5、6): ```json {"name":"装电气件","status":"ACTIVE","stations":[5,6], "steps":[{"seq":1,"name":"装电气件","collectType":"扫码"}]} ``` - 流程3(拧螺丝,绑工位8,2 个扭矩步骤 + 扭矩 RANGE 标准): ```json {"name":"拧螺丝","status":"ACTIVE","stations":[8], "steps":[ {"seq":1,"name":"拧螺丝1","collectType":"扭矩","isTorque":true, "criteria":[{"name":"扭矩","unit":"N·m","logic":"RANGE","min":8,"max":12}]}, {"seq":2,"name":"拧螺丝2","collectType":"扭矩","isTorque":true, "criteria":[{"name":"扭矩","unit":"N·m","logic":"RANGE","min":8,"max":12}]} ]} ``` **系统反应**:新建 3 个流程;把工位2→流程1、工位5和6→流程2、工位8→流程3 绑定;覆盖式重建各流程的工序步骤与考核标准。 **数据变化**: - 工艺流程表新增 3 行,状态=启用(ACTIVE)。 - 工位表:工位2 的流程id=流程1;工位5、工位6 的流程id=流程2;工位8 的流程id=流程3。 - 工序步骤表:流程1 有 2 步;流程2 有 1 步;流程3 有 2 步且"是否扭矩"=是。 - 考核标准表:流程3 的两步各挂 1 条"扭矩 / RANGE / 8~12"标准。 **断言**: - `GET /api/v1/stations` 中工位2/5/6/8 的流程绑定与上表一致。 - `GET /api/v1/process-flows?stationNo=8` 返回流程3,含 2 个扭矩步骤 → 决定 Step 19 拧紧"应拧颗数=2"。 --- ## Step 6:工位派工(工位↔工序,生产日 D) **前置**:Step 5 完成(工位2/5/6/8 已绑流程)。产线系统已登录。生产日 D = 执行当天。 **操作**:生产主管在【产线系统 → 生产管理 → 工位派工】为生产日 D 逐工位派工。 - 接口:`POST /api/v1/station-process/save`(逐条保存,同工位同天同班次唯一) - 4 次请求体: ```json {"stationNo":2,"processCode":1,"effectDate":"2026-09-22","shift":"","operator":"主管01"} {"stationNo":5,"processCode":2,"effectDate":"2026-09-22","shift":"","operator":"主管01"} {"stationNo":6,"processCode":2,"effectDate":"2026-09-22","shift":"","operator":"主管01"} {"stationNo":8,"processCode":3,"effectDate":"2026-09-22","shift":"","operator":"主管01"} ``` **系统反应**:覆盖式保存 4 条派工;保存前做连续性校验(工序号沿工位号 1,2,2,3 单调不降,通过)。 **数据变化**:工位派工表新增 4 行,生效日=2026-09-22、班次=空:(工位2,工序1)、(工位5,工序2)、(工位6,工序2)、(工位8,工序3)。 **断言**: - `GET /api/v1/station-process?effectDate=2026-09-22` 返回 **4** 行,工位→工序映射与上表一致。 - `GET /api/v1/station-process/route?effectDate=2026-09-22` 派生路线:工位串 `2,5,6,8`、工序集合 `1,2,3`。 - 反例(可选验证):把工位4 派为工序1(夹在工位2工序1与工位5工序2之间但破坏单调)时保存被拒,提示"工序编号必须沿工位号单调不降、不可穿插"。 --- ### 阶段二 · 物料进厂:入库 → 检验 --- ## Step 7:结构件入库(铁架子 / 门子 / 螺丝,按批次) **前置**:Step 2(物料档案)、Step 3(A 区)。库房系统已登录。3 种结构件随货带供应商质检报告单号(外部单号,非本系统检验记录)。 **操作**:仓管在【库房系统 → 入库管理 → 结构件入库】按批次录入。 - 接口:`POST /api/inbound/create` - 3 次请求体(`inspectionNo` 检测单号必填、`zoneCode` 区域必填、`quantity`>0): ```json {"inboundType":"purchase","materialCode":"TLJ-01","batchNo":"PC-TLJ-001","quantity":5,"zoneCode":"A","inspectionNo":"QC-TLJ-20260921","operator":"库管01"} {"inboundType":"purchase","materialCode":"MEN-01","batchNo":"PC-MEN-001","quantity":5,"zoneCode":"A","inspectionNo":"QC-MEN-20260921","operator":"库管01"} {"inboundType":"purchase","materialCode":"LS-01","batchNo":"PC-LS-001","quantity":100,"zoneCode":"A","inspectionNo":"QC-LS-20260921","operator":"库管01"} ``` **系统反应**:每笔在事务内建"入库单 + 库存行 + 入库明细"。结构件走批次管理,不允许携带 SN 清单。库存行质量状态先置「未检」(等 Step 9 检验判定)。 **数据变化**: - 入库单表新增 3 行,入库单号形如 `IB<12位>`,数量分别 5/5/100,检测单号回填。 - 库存表新增 3 行(管理方式=1):铁架子批次 PC-TLJ-001 数量=5、门子批次 PC-MEN-001 数量=5、螺丝批次 PC-LS-001 数量=100;质量状态=未检、状态=在库、区域=A、锁定量=0。 - 入库明细表新增 3 行(按批次号 + 数量)。 **断言**: - `GET /api/stock/query?materialCode=TLJ-01` 返回批次 PC-TLJ-001,数量=5、质量状态=未检、状态=在库。 - 门子数量=5、螺丝数量=100,同样质量状态=未检。 - 3 笔入库单数量合计 = 5+5+100 = 110。 --- ## Step 8:电气件入库(4 颗 SN) **前置**:Step 2(电气件档案 DQJ-01 管理方式=2)、Step 3(A 区)。库房系统已登录。 **操作**:仓管在【库房系统 → 入库管理 → 电气件入库】逐个扫 SN 录入。 - 接口:`POST /api/inbound/create` - 请求体(电气件用 `snList`,不带 quantity): ```json {"inboundType":"purchase","materialCode":"DQJ-01","snList":["SN-DQ-001","SN-DQ-002","SN-DQ-003","SN-DQ-004"],"zoneCode":"A","inspectionNo":"QC-DQJ-20260921","operator":"库管01"} ``` **系统反应**:对每个 SN 建一条库存行(管理方式=2,数量=1),SN 全局唯一防重;质量状态置「未检」。 **数据变化**: - 入库单表新增 1 行,数量=4(=SN 个数)。 - 库存表新增 4 行(管理方式=2):SN-DQ-001/002/003/004,各数量=1、质量状态=未检、状态=在库、区域=A。 - 入库明细表新增 4 行(每 SN 一行,数量=1)。 **断言**: - `GET /api/stock/query?materialCode=DQJ-01` 返回 4 条 SN 行,各数量=1、质量状态=未检。 - 重复入库同一 SN 返回冲突提示"SN 已存在"。 --- ## Step 9:来料检验(逐批 / 逐 SN 判合格) **前置**:Step 7、Step 8 完成——库存里已有 3 个批次行 + 4 个 SN 行(质量状态=未检)。库房系统已登录。 **操作**:质检员在【库房系统 → 质量管理 → 来料检验】按批次号/SN 逐条判合格。 - 接口:`POST /api/inspection/create`(`targetId` 传批次号或 SN,系统自动识别类型并定位到那条库存行;`status` 只能"合格/不合格") - 7 次请求体(全部判合格): ```json {"targetId":"PC-TLJ-001","status":"合格","inspectionType":"来料检","inspectQty":5,"passQty":5,"inspector":"质检01"} {"targetId":"PC-MEN-001","status":"合格","inspectionType":"来料检","inspectQty":5,"passQty":5,"inspector":"质检01"} {"targetId":"PC-LS-001","status":"合格","inspectionType":"来料检","inspectQty":100,"passQty":100,"inspector":"质检01"} {"targetId":"SN-DQ-001","status":"合格","inspectionType":"来料检","inspectQty":1,"passQty":1,"inspector":"质检01"} {"targetId":"SN-DQ-002","status":"合格","inspectionType":"来料检","inspectQty":1,"passQty":1,"inspector":"质检01"} {"targetId":"SN-DQ-003","status":"合格","inspectionType":"来料检","inspectQty":1,"passQty":1,"inspector":"质检01"} {"targetId":"SN-DQ-004","status":"合格","inspectionType":"来料检","inspectQty":1,"passQty":1,"inspector":"质检01"} ``` **系统反应**:每条检验在事务内建检验记录,并把定位到的那条库存行质量状态由「未检」改为「合格」。这一步是 Step 14 自动出库能领到货的前提(出库只领"合格"品)。 **数据变化**: - 检验记录表新增 7 行:目标类型(批次/SN 自动判定)、目标id、物料编码(由库存行回填)、状态=合格、检验数量、合格数量。 - 库存表:3 个批次行 + 4 个 SN 行的质量状态 全部由「未检」→「合格」。 **断言**: - `GET /api/inspection/query?materialCode=LS-01` 返回状态=合格 的记录。 - `GET /api/stock/query?materialCode=TLJ-01`:批次 PC-TLJ-001 质量状态=**合格**。 - 7 个目标(3 批次 + 4 SN)质量状态全部=合格;未检数量=0。 - 反例(可选):把某批判"不合格"后,该批在 Step 14 自动出库时被跳过(仅合格品可领料上线)。 --- ### 阶段三 · 工单与排产 --- ## Step 10:建工单(电表箱,数量 1) **前置**:Step 1(产品型号 DX-100,主键 `${productTypeId}`)。产线系统已登录。**产线上当前没有其他「执行中/已暂停」工单**(单工单互斥,否则 Step 12 下发会被拦)。 **操作**:计划员在【产线系统 → 生产管理 → 工单管理】点"新建工单",选产品型号=电表箱、数量=1、完成日期=2026-09-22。 - 接口:`POST /api/v1/work-orders` - 请求体: ```json {"productTypeId":${productTypeId},"productCode":"DX-100","productName":"电表箱","quantity":1,"dueDate":"2026-09-22"} ``` **系统反应**:创建工单,工单号未指定时按规则自动生成 `WO-<当天>-001`;状态恒为「已创建」(不允许直接建到后续状态)。 **数据变化**:工单表新增一行:工单号=`WO-20260922-001`(记作 `${orderNo}`)、产品编码=DX-100、产品名称=电表箱、数量=1、状态=**已创建(CREATED)**、已完工数=0。 **断言**: - `GET /api/v1/work-orders?orderNo=WO-20260922-001` 返回 1 条,数量=1、状态=已创建、已完工数=0。 - 记下工单主键 id(记作 `${orderId}`),Step 12/13 状态流转要用。 --- ## Step 11:日排产(生产日 D,计划 1 台) **前置**:Step 10(工单 `${orderNo}` 状态=已创建,非终态可排产)。 **操作**:计划员在【产线系统 → 生产管理 → 日排产】为该工单排产到生产日 D。 - 接口:`POST /api/v1/daily-plans` - 请求体:`{"orderNo":"WO-20260922-001","planDate":"2026-09-22","planQty":1}` **系统反应**:校验该工单所有日排产累计不超过未开工数量(=数量1−已完工0−在产0=1),本次排 1 台,通过。新建排产,状态默认「待执行」。 **数据变化**:日排产表新增一行:工单号=WO-20260922-001、排产日=2026-09-22、计划数量=1、已完成数量=0、状态=**待执行(PENDING)**。 **断言**: - `GET /api/v1/daily-plans?orderNo=WO-20260922-001` 返回 1 条,计划数量=1、状态=待执行。 - 反例(可选):再排 planQty=1(累计2 > 未开工1)被拒,提示"排产合计数量超过未开工数量"。 --- ## Step 12:工单下发(已创建 → 已下发) **前置**:Step 10(工单状态=已创建)、Step 11(已排产)。产线无其他在产工单。 **操作**:计划员在【工单管理】对该工单点"下发"。 - 接口:`POST /api/v1/work-orders/status` - 请求体:`{"id":${orderId},"status":"RELEASED","reason":"排产完成,下发生产"}` **系统反应**:校验流转合法(已创建可下发)+ 单工单互斥(产线无其他执行中/暂停工单),状态改为「已下发」。 **数据变化**:工单表该行状态 由 已创建(CREATED) → **已下发(RELEASED)**;写状态变更日志(原状态/新状态/原因)。 **断言**: - `GET /api/v1/work-orders/:id`(`${orderId}`)状态=已下发。 - 非法流转(如已创建直接→执行中跳过下发,或→已完成)被拒,提示"不允许从「已创建」变更为「X」"。 --- ## Step 13:工单开工(已下发 → 执行中,联动排产) **前置**:Step 12(工单状态=已下发)、Step 11(排产状态=待执行)。 **操作**:生产主管在【工单管理】对该工单点"开工"。 - 接口:`POST /api/v1/work-orders/status` - 请求体:`{"id":${orderId},"status":"IN_PROGRESS","reason":"产线开工"}` **系统反应**:状态改为「执行中」;联动把该工单「待执行」的日排产置为「执行中」。 **数据变化**: - 工单表:状态 已下发(RELEASED) → **执行中(IN_PROGRESS)**。 - 日排产表:WO-20260922-001 / 2026-09-22 那行状态 待执行(PENDING) → **执行中(PROCESSING)**。 **断言**: - 工单状态=执行中。 - `GET /api/v1/daily-plans?orderNo=WO-20260922-001` 排产状态=执行中。 --- ### 阶段四 · 备料与出库(生产日 D 早上) --- ## Step 14:生成备料单(按排产+派工算料,同步台账,自动出库领合格品) **前置**:Step 4(BOM)、Step 6(生产日 D 的工位派工)、Step 9(库存全部合格)、Step 11(排产日 D 计划 1 台)、Step 13(工单执行中)。**执行当天 = D = 2026-09-22**(生成备料单用"系统当天"匹配派工生效日)。 **操作**:仓管/计划员在【产线系统 → 生产管理 → 备料管理】点"生成备料单",选排产日=2026-09-22。 - 接口:`POST /api/v1/material-requests/generate` - 请求体:`{"planDate":"2026-09-22"}` **系统反应**(一次触发三件事,顺序执行): 1. **算料**:按 BOM 物料的装配工序,拆到当天该工序派工的工位,生成工位级备料单。数量 = 工位分配产量 × 单台用量 ×(1+损耗率)。工序2 派到工位5、6,产量 1 台按工位号拆分给到工位5(工位6 分得 0,不生成)。 2. **同步台账**:把工单级需求总量下发库房「工单物料台账」(按物料聚合,需求量 = 工单数量 × 单台用量 ×(1+损耗率),向上取整)。 3. **自动出库**:对每张备料单按 FIFO 从"合格"库存领料——结构件按批次逐批扣、电气件按 SN 逐颗扣;出库量达标后回写备料单已发出量并置「已锁定」,台账累计出库达标置「领料完结」。 **数据变化**: - **备料单表**新增 4 行(工单 WO-20260922-001,排产日 2026-09-22): | 备料单 | 物料 | 工位 | 工序 | 需求量 | 已发出 | 状态 | |---|---|---|---|---|---|---| | MR…001 | 铁架子 TLJ-01 | 2 | 1 | 1 | 1 | 已锁定(LOCKED) | | MR…002 | 门子 MEN-01 | 2 | 1 | 1 | 1 | 已锁定 | | MR…003 | 电气件 DQJ-01 | 5 | 2 | 2 | 2 | 已锁定 | | MR…004 | 螺丝 LS-01 | 8 | 3 | 3 | 3 | 已锁定 | - **工单物料台账表**新增 4 行:铁架子 总量1/出库1、门子 总量1/出库1、电气件 总量2/出库2、螺丝 总量3/出库3;4 行状态均=**领料完结**。 - **库存表扣减**:铁架子批次 PC-TLJ-001 数量 5→**4**;门子批次 PC-MEN-001 5→**4**;螺丝批次 PC-LS-001 100→**97**;电气件 SN-DQ-001、SN-DQ-002 状态 在库→**出库**(SN-DQ-003/004 仍在库)。 - **出库单表**新增 5 笔(出库即扣库存,状态=已出库):铁架子 1 笔(数量1,批次PC-TLJ-001)、门子 1 笔(数量1)、螺丝 1 笔(数量3,批次PC-LS-001)、电气件 2 笔(每 SN 一笔,各数量1)。 - **出库明细表**:结构件按批次记、电气件按 SN 记。 **断言**: - `GET /api/v1/material-requests?orderNo=WO-20260922-001` 返回 **4** 张备料单,需求量分别 1/1/2/3、已发出=需求量、状态=已锁定。 - 台账:`GET /api/ledger/query?orderNo=WO-20260922-001`(库房侧)返回 4 行,出库量=总量、状态=领料完结。 - 库存:铁架子=4、门子=4、螺丝=97;电气件在库 SN 数=2(SN-DQ-003、SN-DQ-004),出库 SN 数=2(SN-DQ-001、SN-DQ-002)。 - **数量等式(出库阶段)**:铁架子 5=4+1;门子 5=4+1;螺丝 100=97+3;电气件 4=2(在库)+2(出库)。 --- ## Step 15:接料确认(工位收到料) **前置**:Step 14 生成 4 张备料单且已自动出库(已发出量>0)。工位终端已登录(Step 16 前的工位账号)或产线备料页人工确认。 **操作**:工位/仓管对 4 张备料单逐张确认接料(一键确认本批全部剩余)。 - 接口:`POST /api/v1/material-requests/receive` - 4 次请求体(`qty` 传 0 表示"确认本批全部剩余"): ```json {"requestNo":"MR…001","qty":0} {"requestNo":"MR…002","qty":0} {"requestNo":"MR…003","qty":0} {"requestNo":"MR…004","qty":0} ``` **系统反应**:把已接料量累加到"已发出量"上限(不超接);当已发出≥需求量且已接料≥已发出时,备料单状态置「已完结」(送达与接料双完结)。 **数据变化**:4 张备料单:已接料量=已发出量(1/1/2/3),状态 已锁定(LOCKED) → **已完结(DONE)**;回填接料时间、接料人。 **断言**: - `GET /api/v1/material-requests?orderNo=WO-20260922-001` 4 张单 已接料量=已发出量、状态=已完结。 - 配送进度:在途量(已发出−已接料)= 0。 --- ### 阶段五 · 上线装配(3 道工序顺序流转,禁止跳站) --- ## Step 16:工件上线(进线登记) **前置**:Step 13(工单执行中)、Step 15(4 张备料单已完结,料已到工位)。工位终端已登录(工位2 账号)。 **操作**:操作工在【工位终端 → 上线】扫工件序列号,选工单。 - 接口:`POST /api/v1/workpiece/online` - 请求体:`{"sn":"WP-DX-0001","orderNo":"WO-20260922-001","workOrderId":${orderId}}` **系统反应**:登记一台在制工件进线;路线不冗余存储,由当天工位派工实时派生(工位串 2,5,6,8)。当前工序置 0(尚未报任何工序)。 **数据变化**:工件表新增一行:序列号=WP-DX-0001、工单号=WO-20260922-001、状态=**已上线(ONLINE)**、当前工序=**0**。 **断言**: - `GET /api/v1/workpieces/in-process?orderNo=WO-20260922-001` 含 WP-DX-0001,状态=已上线、当前工序=0。 - 重复上线同一序列号被拒(工件已存在)。 --- ## Step 17:报工工序 1(工位 2 · 装铁架子 + 门子) **前置**:Step 16(工件已上线、当前工序=0)、Step 5(工位2 绑「装铁架子门子」流程)、Step 15(铁架子批次 PC-TLJ-001、门子批次 PC-MEN-001 已到工位2)。工位终端已登录(工位2)。 **操作**:操作工在工位2 扫工件号 → 装铁架子、装门子 → 扫两个结构件批次号绑定 → 点"报工"。 - 接口:`POST /api/v1/workpiece/process/report` - 请求体(`binds` 结构件的 `bindValue` 传批次号): ```json {"sn":"WP-DX-0001","processCode":1,"stationNo":2, "binds":[{"materialCode":"TLJ-01","bindValue":"PC-TLJ-001"}, {"materialCode":"MEN-01","bindValue":"PC-MEN-001"}]} ``` **系统反应**:顺序校验(请求工序1 = 当前工序0+1,通过)→ 落装机绑定 → 齐套校验(工序1 的铁架子、门子各至少绑 1 个批次,通过)→ 在同一事务内写报工实绩、推进工件状态。任一步失败整体回滚。 **数据变化**: - 工件装配绑定表新增 2 行:WP-DX-0001 绑 铁架子批次 PC-TLJ-001、门子批次 PC-MEN-001(工序1、工位2)。 - 工件工序实绩表新增 1 行:工序=1、工位=2、状态=已完成、结果=**合格(OK)**、操作人、作业时长。 - 工件表:当前工序 0→**1**、状态 已上线(ONLINE)→**在制(PROCESSING)**。 **断言**: - 工件当前工序=1、状态=在制。 - `GET /api/v1/workpiece/process/records?sn=WP-DX-0001` 有工序1 记录,工位=2、结果=合格。 - 反例:若只绑铁架子不绑门子,报工被拒并返回缺料清单(门子未绑齐)。 --- ## Step 18:报工工序 2(工位 5 · 装 2 颗电气件) **前置**:Step 17(当前工序=1)、Step 5(工位5 绑「装电气件」流程)、Step 15(电气件 SN-DQ-001、SN-DQ-002 已到工位5)。工位终端已登录(工位5)。 **操作**:操作工在工位5 扫工件号 → 逐颗扫 2 个电气件序列号绑定 → 点"报工"。 - 接口:`POST /api/v1/workpiece/process/report` - 请求体(电气件的 `bindValue` 传序列号,必须绑满单台用量 2 颗): ```json {"sn":"WP-DX-0001","processCode":2,"stationNo":5, "binds":[{"materialCode":"DQJ-01","bindValue":"SN-DQ-001"}, {"materialCode":"DQJ-01","bindValue":"SN-DQ-002"}]} ``` **系统反应**:顺序校验(工序2 = 当前工序1+1,通过)→ 落绑定 → 齐套校验(电气件按单台用量逐颗序列号,必须绑满 2 颗,通过)→ 写实绩、推进工件状态。 > 说明:工位6 与工位5 同为工序2(并行位),本工件走工位5 完成工序2;工位6 在本链路不产生该工件的报工记录。 **数据变化**: - 工件装配绑定表新增 2 行:WP-DX-0001 绑 电气件 SN-DQ-001、SN-DQ-002(工序2、工位5)。 - 工件工序实绩表新增 1 行:工序=2、工位=5、状态=已完成、结果=合格(OK)。 - 工件表:当前工序 1→**2**、状态=在制(PROCESSING)。 **断言**: - 工件当前工序=2。 - `GET /api/v1/workpiece/process/records?sn=WP-DX-0001` 有工序2 记录,工位=5、结果=合格。 - 反例:只绑 1 颗电气件(少于单台用量2)报工被拒,提示电气件未绑齐。 --- ## Step 19:拧紧上报(工位 8 · 拧 2 颗螺丝,扭矩判定) **前置**:Step 5(工位8 绑「拧螺丝」流程,含 2 个扭矩步骤,扭矩标准 RANGE 8~12)、Step 15(螺丝批次 PC-LS-001 已到工位8)。工件当前工序=2(拧紧属工序3 工位,先采拧紧数据再报工序3)。工位终端已登录(工位8)。 **操作**:拧紧工具/操作工在工位8 对 2 颗螺丝分别上报扭矩。 - 接口:`POST /api/v1/torque/report`(工位终端经 `POST /api/internal/torque/report` 转发) - 2 次请求体(`strain`=扭矩值 N·m,落在 8~12 内): ```json {"sn":"WP-DX-0001","workOrderNo":"WO-20260922-001","stationNo":"8","screwNo":"1","strain":10,"angle":95,"operator":"操作工08"} {"sn":"WP-DX-0001","workOrderNo":"WO-20260922-001","stationNo":"8","screwNo":"2","strain":11,"angle":92,"operator":"操作工08"} ``` **系统反应**:每颗写一条拧紧记录;并按「扭矩 / RANGE 8~12」标准自动判定,各写一条步骤考核数据(10、11 均在区间内 → 合格)。 **数据变化**: - 拧紧记录表新增 2 行:WP-DX-0001 / 工位8 / 螺丝序号1(扭矩10)、序号2(扭矩11),结果=合格(OK)。 - 步骤考核数据表新增 2 行:考核标准=扭矩、判定逻辑=区间(RANGE)、值=10 与 11、是否合格=是。 **断言**: - `GET /api/v1/torque/records?sn=WP-DX-0001&stationNo=8` 返回 2 条,扭矩=10、11,结果=合格。 - 拧紧汇总「应拧颗数=2、实拧颗数=2、合格=2、不合格=0」,满足判定=是。 - 反例:上报扭矩=13(超上限12)时该条判定=不合格(NG),并触发一条「拧紧扭矩不合格」预警。 --- ## Step 20:报工工序 3(工位 8 · 装螺丝批次) **前置**:Step 18(当前工序=2)、Step 19(2 颗螺丝已拧紧合格)、Step 5(工位8 绑「拧螺丝」流程)。工位终端已登录(工位8)。 **操作**:操作工在工位8 扫工件号 → 扫螺丝批次号绑定 → 点"报工"。 - 接口:`POST /api/v1/workpiece/process/report` - 请求体(结构件螺丝 `bindValue` 传批次号,至少绑 1 个批次): ```json {"sn":"WP-DX-0001","processCode":3,"stationNo":8, "binds":[{"materialCode":"LS-01","bindValue":"PC-LS-001"}]} ``` **系统反应**:顺序校验(工序3 = 当前工序2+1,通过)→ 落绑定 → 齐套校验(螺丝至少绑 1 个批次,通过)→ 写实绩、推进工件状态。工件走完全部 3 道工序。 **数据变化**: - 工件装配绑定表新增 1 行:WP-DX-0001 绑 螺丝批次 PC-LS-001(工序3、工位8)。 - 工件工序实绩表新增 1 行:工序=3、工位=8、状态=已完成、结果=合格(OK)。 - 工件表:当前工序 2→**3**、状态=在制(PROCESSING)。 **断言**: - 工件当前工序=3(= 路线工序总数)。 - `GET /api/v1/workpiece/process/records?sn=WP-DX-0001` 有工序1/2/3 三条实绩,结果均=合格。 - 反例:在工序2 未完成时直接报工序3(跳站),被拒提示"工序顺序不符,应在工位2 报工"。 --- ### 阶段六 · 完工与成品入库 --- ## Step 21:完工(兜底齐套校验 + 成品回流 + 反冲核销) **前置**:Step 20(工件当前工序=3,三道工序物料均已绑齐)。工位终端已登录(下线工位)。 **操作**:操作工在【工位终端 → 下线完工】扫工件号,确认结构件批次与电气件序列号清单,点"完工"。 - 接口:`POST /api/v1/workpiece/done` - 请求体(`batchItems` 结构件批次号、`serialItems` 电气件序列号): ```json {"sn":"WP-DX-0001", "batchItems":["PC-TLJ-001","PC-MEN-001","PC-LS-001"], "serialItems":["SN-DQ-001","SN-DQ-002"]} ``` **系统反应**(一个事务内顺序完成 5 件事): 1. **兜底齐套校验**:复核工艺路线中每道工序的装配物料是否都绑齐(工序1 铁架子+门子、工序2 电气件×2、工序3 螺丝),通过。 2. **工件置完工**:工件状态改「已完工」,记完工时间。 3. **建关联追溯**:以成品序列号为主键,记录工单号、经过的工位串(`2,5,6,8`)、结构件批次清单、电气件序列号清单,形成"这台成品用了哪些料"的正向追溯。 4. **进度回写**:工单已完工数 +1(状态回「执行中」,不自动置已完成);日排产已完成数 +1,达计划量 1 → 排产置「已完成」。 5. **成品回流库房 + 反冲核销**:把成品作为一条新库存回流到库房(成品序列号=工件序列号);反冲按 BOM 单台用量核销工单台账的"已消耗量"(**只核销台账,不再动库存——库存已在 Step 14 出库时扣过**)。 **数据变化**: - 工件表:WP-DX-0001 状态 在制(PROCESSING)→**已完工(DONE)**,完工时间回填。 - 关联追溯表新增 1 行:成品序列号=WP-DX-0001、工单号=WO-20260922-001、工位串=2,5,6,8、批次清单=[PC-TLJ-001,PC-MEN-001,PC-LS-001]、序列号清单=[SN-DQ-001,SN-DQ-002]。 - 工单表:已完工数 0→**1**、状态=执行中(IN_PROGRESS)。 - 日排产表:已完成数 0→**1**,状态 执行中(PROCESSING)→**已完成(DONE)**。 - 库房库存表新增 1 行(成品回流):管理方式=2、品类=**成品(3)**、物料编码=DX-100、序列号=WP-DX-0001、数量=1、质量状态=合格、状态=在库、入库单号=`MES:WO-20260922-001`。 - 工单物料台账表:铁架子已消耗 0→1、门子 0→1、电气件 0→2、螺丝 0→3(消耗量=单台用量×(1+损耗率) 取整:螺丝=2×1.5=3)。 **断言**: - 工件状态=已完工。 - `GET /api/v1/work-orders?orderNo=WO-20260922-001` 已完工数=1。 - `GET /api/v1/daily-plans?orderNo=WO-20260922-001` 已完成数=1、状态=已完成。 - 库房侧 `GET /api/stock/query?materialCode=DX-100` 返回 1 条成品库存,序列号=WP-DX-0001、品类=成品、数量=1、质量状态=合格、状态=在库。 - 台账已消耗量:铁架子1、门子1、电气件2、螺丝3;核销不产生新出库单、不再改动库存数量(螺丝库存仍=97)。 --- ## Step 22:工单完工流转(执行中 → 已完成) **前置**:Step 21(工单已完工数=1 = 工单数量1,状态=执行中)。 **操作**:计划员在【产线系统 → 工单管理】对该工单点"完工"。 - 接口:`POST /api/v1/work-orders/status` - 请求体:`{"id":${orderId},"status":"DONE","reason":"1 台已全部完工"}` **系统反应**:校验流转合法(执行中可置已完成),状态改「已完成」。这是工单终态。 **数据变化**:工单表:状态 执行中(IN_PROGRESS)→**已完成(DONE)**;写状态变更日志。 **断言**: - `GET /api/v1/work-orders/:id` 状态=已完成、已完工数=1、数量=1。 - 已完工数=数量,工单闭合。 --- ### 阶段七 · 多余料回仓库 + 成品追溯 --- ## Step 23:工位退料(工位 8 · 螺丝用剩 1 颗) **前置**:Step 21 完工。螺丝单台标准备料 3 颗(含 50% 损耗预留),实装拧 2 颗,剩 1 颗需退回库房。工位终端已登录(工位8)。 **操作**:操作工在【工位终端 → 退料】选工单、物料=螺丝、数量=1、原因="装配用剩退库",提交。 - 接口:`POST /api/return-material`(工位终端 → 产线内部接口 → 库房预建退库单) - 请求体: ```json {"orderNo":"WO-20260922-001","stationNo":8,"sn":"WP-DX-0001", "materialCode":"LS-01","materialName":"螺丝","spec":"M4×10","unit":"颗", "qty":1,"reason":"装配用剩退库"} ``` **系统反应**:产线系统落一条退料事件日志,转调库房预建一张「待确认收货」退库单(来源=工位)。库存在库管确认收货后才加回。 **数据变化**:库房退库单表新增 1 行:退库单号=`RT<...>`、来源类型=工位(station)、工单号=WO-20260922-001、工位=8、物料=LS-01 螺丝、数量=1、原因=装配用剩退库、状态=**待确认(PENDING)**。 **断言**: - 库房侧退库单列表存在该单,状态=待确认、数量=1。 - 此刻螺丝库存仍=97(尚未加回,等 Step 24 确认)。 --- ## Step 24:库管确认收货(退库单 → 已收货,库存加回) **前置**:Step 23(退库单待确认)。库房系统已登录(库管账号)。 **操作**:库管在【库房系统 → 退库管理】对该退库单点"确认收货",退库类型选"剩余物料",指定回退库位 A 区、批次 PC-LS-001。 - 接口:`POST /api/return-order/confirm` - 请求体:`{"returnNo":"RT<上一步单号>","returnType":"surplus","zoneCode":"A","batchNo":"PC-LS-001"}` **系统反应**:在一个事务内把退库单置「已收货」并把库存加回。剩余物料(surplus)按口径置质量状态「**未检**」——用剩的料不直接判合格,需复检后方可再上线,因此不并入原「合格」批次行,而是独立成一条未检库存行(同批次号 PC-LS-001、数量 1、质量状态未检)。 **数据变化**: - 退库单表:状态 待确认(PENDING)→**已收货(RECEIVED)**,回填收货人、收货时间。 - 库房库存表新增 1 行(螺丝退库):管理方式=1、物料=LS-01、批次=PC-LS-001、数量=1、质量状态=**未检**、状态=在库、区域=A、入库单号=`RET:RT<单号>`。 - 工单物料台账表(螺丝行):已退回量 0→**1**;净领用(已出库 3 − 已退回 1 = 2)< 需求量 3,状态由「领料完结」**回退为「进行中」**(退料回补缺口,允许后续再补料)。 **断言**: - 退库单状态=已收货。 - `GET /api/stock/query?materialCode=LS-01`:合格批次 PC-LS-001 数量=97(未变),另有一条未检 PC-LS-001 数量=1;螺丝在库总量=97+1=**98**。 - 台账螺丝行:已出库=3、已退回=1、净领用=2、已消耗=3、状态=进行中。 - **数量等式(螺丝全链路闭合)**:入库 100 = 出库 3 + 期末在库 97;出库 3 = 装进成品 2 + 退回 1;退回 1 → 未检库存 1。总库存 98 = 97(合格) + 1(未检退回)。 --- ## Step 25:成品追溯(按成品序列号回查全链路) **前置**:Step 21(关联追溯已建)、Step 19(拧紧记录)、Step 17~20(三道工序实绩)。产线系统或工位终端已登录。 **操作**:质量员在【产线系统 → 追溯查询】扫成品序列号 WP-DX-0001。 - 接口:`GET /api/v1/trace?sn=WP-DX-0001`(工位终端经 `GET /api/trace?sn=` 代理) **系统反应**:以成品序列号汇总回查:工件状态、工单、经过的工位串、每道工序的报工时间与操作人、装机的结构件批次与电气件序列号、拧紧扭矩数据。 **数据变化**:只读查询,不改数据。 **断言**: - 追溯返回:成品序列号=WP-DX-0001、工单=WO-20260922-001、工件状态=已完工、工位串=2,5,6,8。 - 工序时间线含工序1(工位2)、工序2(工位5)、工序3(工位8) 三条实绩,结果均合格。 - 物料清单:铁架子批次 PC-TLJ-001、门子批次 PC-MEN-001、螺丝批次 PC-LS-001、电气件序列号 SN-DQ-001 与 SN-DQ-002。 - 拧紧数据:2 颗,扭矩 10 与 11,均合格。 --- ## 四、全链路数量等式总断言(跑完必须全部闭合) | 物料 | 入库(Step7/8) | 出库到工位(Step14) | 装进成品(Step17~21) | 退回库房(Step23/24) | 期末在库 | |---|---|---|---|---|---| | 铁架子 TLJ-01 | 5 | 1 | 1 | 0 | 4 | | 门子 MEN-01 | 5 | 1 | 1 | 0 | 4 | | 电气件 DQJ-01 | 4(SN) | 2(SN001/002) | 2 | 0 | 2(SN003/004 在库) | | 螺丝 LS-01 | 100 | 3 | 2 | 1 | 98(97合格+1未检) | | 成品 DX-100 | — | — | 下线 1(WP-DX-0001) | — | 1(合格·在库) | **闭合校验(逐条必须成立)**: - 铁架子:5 = 4(在库) + 1(装进成品)。 - 门子:5 = 4(在库) + 1(装进成品)。 - 电气件:4 = 2(SN003/004 在库) + 2(SN001/002 装进成品)。 - 螺丝:100 = 97(合格在库) + 3(出库);出库 3 = 2(装进成品) + 1(退回未检);期末在库 98 = 97 + 1。 - 工单:数量 1 = 已完工 1;工单状态=已完成。 - 日排产:计划 1 = 已完成 1;排产状态=已完成。 - 台账(Step21 反冲后、Step24 退库后最终态):铁架子 已出库=已消耗=总量=1、状态领料完结;门子 已出库=已消耗=总量=1、状态领料完结;电气件 已出库=已消耗=总量=2、状态领料完结;螺丝 已出库=总量=3、已消耗=3(按 BOM 单台标准量 2×1.5 计)、已退回=1、净领用=2、状态因退料回退为进行中。 - 关联追溯:成品 WP-DX-0001 的批次清单 3 项 + 序列号清单 2 项,与装进成品列完全一致。 --- ## 五、回归后数据复位(供重复执行) > 本链路会写入成品序列号 WP-DX-0001(全局唯一)、批次 PC-* 与序列号 SN-DQ-*(全局唯一)。重复执行前需清理,否则上线/入库会撞唯一约束。 复位顺序(与建数据相反): 1. 删除关联追溯、工件工序实绩、工件装配绑定、拧紧记录、步骤考核数据(按 sn=WP-DX-0001)。 2. 删除工件(WP-DX-0001)、日排产、工单(WO-20260922-001)及其状态日志。 3. 删除备料单、工单物料台账(按 orderNo)。 4. 删除库房退库单、出库单及明细、入库单及明细、检验记录、库存行(成品 DX-100 与 4 种零部件的批次/SN 行)。 5. 删除工位派工(生产日 D)、工艺流程与工序步骤/考核标准、产品物料清单、物料档案、产品型号、区域 A(如与其他用例共用则保留)。 > 若只需快速重跑,可保留主数据(Step1~6),仅清理 Step7 起的库存/单据/工件数据,并从 Step7 重新入库。