老WMS操作手册拆解:状态机、业务约束与二次开发校验

发布时间:2026/11/3 19:41:44
老WMS操作手册拆解:状态机、业务约束与二次开发校验

简介:《WMS系统操作手册》面向仓库管理员、供应链管理者及ERP/WMS实施与运维人员。文档围绕浙江三花智能控制股份有限公司自主开发的Web端仓储管理系统,梳理从销售订单编制、提交、审核到订单变更的完整操作路径,并覆盖主生产计划编辑、审核、抛砖与变更,以及事业部入库、物流部验货上架等场景;各章节按流程说明、操作项拆解、界面演示、注意事项的顺序展开,适合作为企业内部培训教材,或供学习者对照系统界面逐步演练。资源包共1个文件,为docx格式的操作手册,压缩包约23.02MB,内置大量界面截图,图文对照便于按模块查阅,也方便打印成册或摘取章节做培训材料。该资源已有1659人学习,读者可借此掌握WMS各业务环节的规范操作与关键控制点,也能为新系统上线前的流程梳理和岗位交底提供参考。

1. 一份只有操作手册的 WMS,反而更值得拆

接手一套跑了好几年的仓储系统,最容易翻车的场景不是代码看不懂,而是整个系统只剩一份 WMS 操作手册,新人培训全靠老员工口口相传。手上的这份资料来自某制造集团应用开发中心的 WMS 项目,版本 V1,编制时间 2017 年,正文覆盖销售订单编制审核、订单变更、主生产计划编辑与抛转、事业部入库、物流部验货上架、拣货装车、返工与形态转换、退货共十余条业务线,末尾还挂了一份常见问题联系清单。它更适合当作「业务规则说明书 + 二次开发需求来源」来读,不适合当成新人教程。适合两类人:一类是要接手老系统运维、得快速搞清每个角色在哪个环节卡住的;另一类是要照着手册把流程重做进新系统、需要知道哪些字段是硬约束的。

2. 手册骨架与运行环境:先摸清模块边界再谈怎么跑

拿到手册别急着从头翻,先看目录。这份文档的三级标题看着零散,其实按角色和业务域能重排成五块:订单域、计划域、仓储执行域、逆向域、附录。重排完再回头看每一节的「流程及环节简要说明—主要操作项说明—操作流程演示」三段式,你会发现它是同一个模板套出来的,理解了模板就等于理解了整本手册的写法。

2.1 从目录反推模块边界

手册正文的编号从 3.1 排到 3.12,中间还有断号,直接读会迷路。我一般按业务域重新归档一遍,落到目录上大概是这样:

# WMS 操作手册按业务域重排(章节号对应原手册编号) wms-manual/ ├── 01-overview/ # 1 引言、2 软件概述:用途、BS 架构、访问方式 ├── 02-order/ # 3.1 销售订单编制/提交/审核 3.2 销售订单变更 ├── 03-plan/ # 3.3 主生产计划编辑/审核/抛转 3.4 主生产计划变更 ├── 04-inbound/ # 3.5 事业部入库申请 3.6 物流部验货、上架 ├── 05-outbound/ # 3.7 物流部拣货、装车 3.8 返工、形态转换 ├── 06-reverse/ # 3.9 返工功能 3.12 退货功能 └── 07-appendix/ # 4.1 常见问题联系清单

这一层归档的价值在于标出角色边界。02-order的操作者是业务员、内务员、所长、营业管理岗;03-plan换成了制造部计划员和主管;04-inbound往下是事业部成品仓仓管员、运转工、物流部验货员;05-outbound是物流部拣货和装车岗。每个域换一次人,换人处就是审批节点,也是权限配置最容易配错的地方。

提示:手册里的「抛砖」是原文用词,按上下文语义应为「抛转」,指把主生产计划转交给事业部执行。做二次开发时字段名、按钮名、接口名三处必须统一成同一个词,否则前后端联调时会互相找不到。

2.2 单据状态机:保存、提交、驳回、弃审其实是同一套骨架

手册把「保存」「提交」「驳回」「弃审」「删除」拆在十几个小节里各讲一遍,读起来像是每张单据各有一套规则。实际不是,这套系统所有单据共用一套状态机,只是每张单据允许的流转边不一样。把这层抽出来,后面看任何一节都能对上号。

# 单据公共状态机:手册中散落在各章节的按钮,本质是下面这张流转表 STATES = ("DRAFT", "SUBMITTED", "APPROVING", "APPROVED", "THROWN", "CLOSED") TRANSITIONS = { ("DRAFT", "save"): "DRAFT", # 保存:生成单据号,仍处草稿 ("DRAFT", "submit"): "SUBMITTED", # 提交:流入下一环节,待办出现 ("SUBMITTED", "approve"): "APPROVED", # 审核通过 ("SUBMITTED", "reject"): "DRAFT", # 驳回:退回上一环节编制人 ("APPROVED", "throw"): "THROWN", # 抛转:商贸组织转事业部执行 ("APPROVED", "unaudit"): "DRAFT", # 弃审:已审单据退回重编 ("THROWN", "close"): "CLOSED", # 关闭:余量归零或返工主计划关闭 } def transit(doc, action, operator): key = (doc.status, action) if key not in TRANSITIONS: raise BizError(f"单据 {doc.no} 当前状态 {doc.status} 不支持 {action}") if doc.status == "SUBMITTED" and action == "reject" and doc.is_first_node: raise BizError("流程第一个环节不允许驳回") # 手册明确写的限制 return TRANSITIONS[key]

这段代码要看的不是语法,是三条业务约束。第一,save落在DRAFT上,说明保存只生成单据号不推进流程,所以草稿被误删不会影响业务。第二,reject只能从SUBMITTED出发,is_first_node为真时直接拦掉,对应手册里「当流程处理第一个环节无法执行驳回功能」。第三,unaudit是审核之后才有的后悔药,手册里叫「单据弃审功能」,弃审完单据回到编制人手上,可以重编也可以删除。

2.3 运行环境与账号体系:BS 架构下的三个前提

软件概述写得很短:BS 架构,浏览器访问,建议 Chromium 内核浏览器,必须在特定内网环境使用。这三句话翻译成运维动作就是三件事——浏览器版本、网络可达、账号组织选对。前两个好办,第三个是新人最常卡的地方:登录页第一行选组织,第二行填员工编号,第三行填密码,账号密码默认都是员工编号。组织选错不会报错,只会看到一片空白的待办列表。

# 排查"页面打不开"的连通性三步(地址为示例,按实际环境替换) curl -I --max-time 5 http://10.12.34.56:8080/wms/login # 服务是否存活,看 HTTP 状态码 nc -zv 10.12.34.56 8080 # 端口是否放通,不通就是网络策略问题 curl -I --max-time 5 http://10.12.34.56:8080/wms/health # 健康检查,返回 503 多半是应用连不上库

--max-time 5是必须加的,内网故障时请求会一直挂着,不设超时排查人员会以为是自己卡了。nc -zv只探端口不做业务请求,用来区分「网络不通」和「应用挂了」,这两种现象在用户侧表现完全一样,都是转圈。

注意:登录账号默认是员工编号,密码也默认是员工编号,这是典型的历史遗留设计。做安全改造时不要直接改默认密码规则,老账号没有邮箱和手机号可用来找回,一改就是大面积锁号,得先补一套管理员重置流程。

2.4 哪些字段是自动带出的,为什么不能随便改成手填

手册在销售订单、入库申请两节里反复出现「系统自动带出」「由系统自动分配」,这些字段构成了整套系统的隐性数据契约,二次开发时把它们改成手填,等于把数据一致性交给用户。

字段来源是否可改改动后果
币种、立账条件客户主数据否改错会导致应收对不上账
销售员销售部门联动部门内可选跨部门选不到人,属正常
供应商订单方式为 OEM 时才必填是非 OEM 订单填了会被下游拒收
操作仓库、业务部门登录账号绑定否换仓要换账号,不能页面上切
核算年系统按业务日期分配否跨月入库会影响财务归属月份
库存操作类型单据类型决定二选一事业部入库只能选成品入库

这张表看着平淡,实际是排查工单时最常翻的一页。用户说「这个单子物流部看不到」,八成是因为业务部门或操作仓库绑错了账号,单据提交到了另一个组织的待办池里。

3. 订单与前计划段:从销售订单到主生产计划抛转

这一段是整本手册里逻辑密度最高的部分,涉及国内、国际两条订单录入流程,以及销售订单变更、主生产计划编制审核、主生产计划变更四张单据。四张单据之间存在强依赖:订单不审核,计划员看不到看板数据;主计划不抛转,事业部那边就没有生产任务。搞清楚依赖顺序,比记住每个按钮在哪重要得多。

3.1 销售订单编制:必填项、自动带出与可用量锁定

手册把界面要素拆成九条,我按「谁决定谁」重新归了一下类。客户是源头,选了客户,币种和立账条件自动带出;订单方式决定是否要填供应商;销售部门和销售员是联动下拉,部门变了人选范围跟着变;表格区的料号、数量、客户需求日期三列必填,项目号选填但要理解它的默认逻辑——选完客户再新增行,系统会按客户与项目号的绑定关系带出默认项目号,可以手工改;订货号也是选填,填了会自动带出料号。

国内流程是「业务员录入 → 所长提交 → 营业管理岗审核」,国际流程是「内务员录入 → 单证处审核」,两条流程共用同一个录入界面,差别只在审批链。这个设计挺常见,配置化审批链挂在单据类型上,前端不区分。

保存之后系统生成单据号、落草稿,同时做一件容易被忽略的事:库存自由量大于零时,保存动作会把可用量锁住,锁定结果直接显示在表格里。这条规则意味着「先保存后删除」不是无副作用的,草稿期间已经占用了可用量,别人下同样的料号可能就提示不够。

# Excel 导入前的行级校验,模板列与集团 ERP 保持一致 REQUIRED = ["客户编码", "订单方式", "销售部门", "销售员", "料号", "数量", "客户需求日期"] def check_row(row, idx): errs = [] for col in REQUIRED: if not str(row.get(col, "")).strip(): errs.append(f"第{idx}行:{col} 为空") if row.get("订单方式") == "OEM" and not row.get("供应商"): errs.append(f"第{idx}行:OEM 订单必须指定供应商") if float(row.get("数量") or 0) <= 0: errs.append(f"第{idx}行:数量必须大于 0") if not (row.get("料号") or row.get("订货号")): errs.append(f"第{idx}行:料号与订货号至少填一个") return errs

导入是最容易出问题的地方,因为错误提示往往只告诉你「导入失败」,不告诉你哪一行错。我的做法是先在本地跑一遍这段校验,把错误一次性收集完再贴回给用户,避免用户改一行导一次、来回十几趟。日期列要统一成yyyy-MM-dd,Excel 里被识别成日期格式的单元格导出后会变成序列号,这是血泪经验里最常见的一条。

3.2 销售订单变更:看板取数、变更原因与弃审

订单变更不是直接在原单上改,而是新起一张变更单,通过看板把原销售订单捞出来。看板支持按业务单号、物品、项目号、订货号、客户代码、需求时间筛选,筛选条件要手工添加,选中的行点「确认选择」回填到变更单表单,然后改需求数量或日期。

变更单上有几个自动生成的字段值得记:业务单号、发起部门、发起人、发起时间由系统匹配,变更原因必须用文字写清楚,这是后续追溯的唯一凭据。保存后系统生成单号落草稿,提交后流转到制造部计划处指定人员做变更指令接受。

这里有个手册自身的小坑:变更单保存那一条写的是「系统自动生成返工单号」,从上下文看应该是变更单号,属于文档笔误。真按字面去核对返工单,会找不到对应单据。

弃审功能用在驳回之后。业务被驳回,单据回到营业部编制人手上,编制人可以重新编制,也可以直接删掉取消这次变更。弃审和驳回不是一回事:驳回是审核人把单子退回去,弃审是编制人主动把已经审核通过的单子撤回重编。

3.3 主生产计划编辑、审核与抛转:商贸组织为什么多一步

计划员的工作起点是销售订单看板。勾选已审核的订单、确认选择,订单行进入主生产计划编辑单,保存后生成业务单号,同时编制人默认取当前登录账号。单据上有个 OEM 开关,勾了就必须选供应商,用于委外生产场景。

真正需要理解的是「抛转」这一步。商贸类组织自己没有生产实体,主生产计划编制、审核完之后要抛给对应事业部去执行;有生产实体的组织审核完直接提交即可。操作路径是「协同 → 抛转 → 确认 → 保存 → 提交 → 确认提交」,六步里前两步是选目标组织,后四步跟普通提交一样。判断依据手册给得很明确:商贸组织下的主生产计划都需要抛转,其余直接提交。

// 抛转前的前置校验:别等点完六步才发现目标组织选错 function checkThrow(plan, targetOrg) { if (plan.status !== 'APPROVED') throw new Error('只有已审核的主计划可抛转'); if (!plan.lines.every(l => l.qty > 0)) throw new Error('存在数量为 0 的行,先清理再抛转'); if (targetOrg.id === plan.orgId) throw new Error('目标组织不能与编制组织相同'); const left = plan.lines.reduce((s, l) => s + (l.qty - l.inboundQty), 0); // 剩余未入库量 if (left <= 0) throw new Error('该主计划已全部入库,无需抛转'); return true; }

left这个剩余未入库量是后面所有变更操作的核心指标。抛转不是把整张单子送过去,而是把剩余量送给事业部,事业部每入库一次,剩余量减一次,减到 0 这条抛转关系就关闭了。

3.4 主生产计划变更的三条路径,选错就得多干一遍

手册 3.4 节写得最绕,但它其实是三条并列的处理路径,选哪条取决于「事业部有没有入库」和「主计划是不是返工产生的」两个条件。

场景判断条件操作位置结果
抛转后事业部未完成入库已入库量 < 销售订单量销售订单变更变更剩余未入库的主计划量
抛转后事业部已全部入库已入库量 = 主计划量销售订单编辑页的订单取消关闭发货行,变更后数量填 0
返工归还生成的返工主计划返工单类型选错导致未归还对应组织返工申请页「更多」箭头里关闭返工主计划

第一条的约束要记牢:变更后的数量必须大于等于事业部已入库数量、小于销售订单数量。变更后数量正好等于已入库量时,该事业部剩下的主计划数量被关闭。第二条常用于事业部返工单选错类型、导致主计划没归还的情况,制造部用它把主生产计划补回去,让数量和发货计划对齐,操作是先输销售订单号查询、选中料品行、在右下角「变更后数量」填 0、保存。第三条藏在返工申请页的「更多」小箭头里,不看手册基本发现不了。

4. 仓储执行段:入库、上架、拣货装车与逆向闭环

仓储执行域覆盖 3.5 到 3.9 再加 3.12,是手册里篇幅最大的一段。事业部入库写得极细,字段级说明有二十条;物流部验货上架、拣货装车则只有流程标题和注意事项,具体操作靠演示截图。这种详略不均的老手册很常见——写的人是谁,哪一节就写得多。

4.1 事业部入库申请:从主计划看板勾选到生成入库单

流程是四个岗位接力:事业部计划处按销售订单完成生产(走 ERP 生产流程)、成品仓仓管员根据流转卡在系统里编制事业部入库申请单、打印物资入库单和外箱条码贴到包装箱对应区域、运转工把实物和单据一起搬到物流部待验货区。

编制环节的几个要点:操作仓库和业务部门都由账号绑定带出,仓管员不用选也选不了;库存操作类型只有成品入库和返工入库两个选项,事业部入库必须选成品入库;供应商名称一栏显示的是主计划订单项目号对应的客户名称,名字叫供应商但填的是客户,这是历史字段命名问题;来源仓库和来源部门在事业部成品入库场景下不填。

数量有两个关键列。「可用数量」是该订单当前剩余可入库数量,「总数量」是销售订单的总出货目标数。录入数量不能超过可用数量,超了保存不了。实际入库量大于看板单行数量时,勾选两行同项目号、料号、订货号的主计划一起带过来。

注意:同项目号同料号但订货号不同的主生产计划,在系统里是两种独立库存;有订货号和无订货号的主计划也各自独立互不影响。核对数量时按「项目号 + 料号 + 订货号」三元组匹配,少一个维度就会算错可入库量。

4.2 物流部入库:验货、上架与库存状态迁移

手册这一节主要给流程图和注意事项,字段说明很少。按同类系统的常见做法,验货上架环节至少包含三件事:核对单据与实物、记录质检结论、分配上架库位。核对方式是扫外箱条码,扫出来的入库单号、料号、批次与待验区实物比对,对不上的挂异常;质检结论分合格、让步接收、不合格,不合格的进不良品区不进可用库存;上架库位一般由系统按库区、容量、周转规则推荐,允许手工指定但要受库区权限约束。

状态迁移是这一节最该写清楚但没写清楚的部分。事业部提交的入库单到物流部只是「待验」,库存在系统里还不是可用量;验货通过并完成上架确认之后,库存才从待验状态转成可用状态,这时候销售订单那边锁定的可用量才算真正兑现。很多「明明入库了为什么还提示库存不足」的问题,根源就在上架确认这一步没点。

-- 查一张单为什么卡在待验:看状态与上架时间的差异 SELECT d.doc_no, d.status, d.org_id, d.warehouse_id, d.submit_time, l.putaway_time, l.qc_result FROM wms_doc d JOIN wms_doc_line l ON l.doc_id = d.id WHERE d.doc_no = 'RK20240315001';

status是SUBMITTED而putaway_time为空,说明单到了物流部但没人做上架确认;qc_result为空则是质检结论还没录。这两个字段分开看,能快速判断卡在哪个岗位。

4.3 物流部出库:拣货、复核与装车过账

出库段手册只给了「拣货、装车」的流程标题,具体步骤同样按同类系统的常见做法补:发货计划下达到物流部后生成拣货任务,任务按库位路径排序减少走动;拣货员扫码拣货,扫错料号当场报警;拣完进复核区二次扫码核对;核对通过装车,装车完成做出库过账,库存扣减、单据关闭。

有两处容易翻车。第一,拣货任务的库位排序依赖库位主数据的坐标,库位坐标没维护的组织,任务顺序是乱的,拣货员会来回跑。第二,装车过账和实际发运时间往往不一致,月底对账时以哪个为准要在实施阶段就定下来,否则财务和物流两边永远对不上数。

# 拣货异常时按单号捞日志,看是扫码失败还是库存校验拦截 grep -n "SO20240315007" /opt/wms/logs/wms-app.log | tail -50 grep -n "QTY_NOT_ENOUGH\|BARCODE_MISMATCH" /opt/wms/logs/wms-app.log | tail -20

第一行捞这张单的全部日志,第二行按错误码过滤看有没有库存不足或条码不匹配的记录。日志里带请求号的话,顺着请求号能把一次扫码的完整链路串起来。

4.4 返工、形态转换与退货:逆向单据怎么闭环

返工在手册里出现了两次,3.8 是物流部返工出库,3.9 是返工功能本身,容易看成两件事。实际是一条闭环:成品需要返工,先从成品仓做出库到车间,单据类型选返工出库;车间处理完再入库,入库时库存操作类型选返工入库,而不是成品入库。这一选错,库存就回到了成品口径,返工履历断掉,后面制造部想归还主计划也归不了——手册 3.4 节专门提到「事业部返工单选错类型导致没有归还主计划」就是这个情况。

形态转换是一进一出两张单,比如整箱拆零、组件拆解、包装更换。要点是转换前后料号可能相同也可能不同,相同料号靠批次区分,不同料号要建转换关系表。转换单不做金额核算,只做数量与库存状态的迁移。

退货走销售退回单,退货入库后先落待检区,质检判定良品才转可用库存,不良品走报废或返工流程。手册在注意事项里强调退货单要关联原发货单,不然批次追溯就断了。

5. 避坑与排查:现场五类卡单记录

手册第 4 章只有一份「常见问题联系清单」,谁负责哪个模块、电话多少,没有一条讲现象和原因。下面这五条是照着流程跑下来最容易撞上的,按「现象 → 原因 → 解决」记。

5.1 单据流转类卡单

第一条,提交了对方看不到。现象是仓管员说入库单已提交,物流部待办里空空如也。原因多半是登录组织选错,单据提交到了另一个组织的待办池,或者账号绑定的业务部门与该单据的业务部门不一致。解决办法是先按单据号查状态和org_id,确认单据归属组织,再核对操作人账号绑定的组织与仓库,不一致就换账号重登,不要试图在页面上改归属。

第二条,驳回按钮点不动。现象是流程第一个环节的操作人找不到驳回按钮或点了无反应。原因就是手册写死的那条规则:流程第一个环节无法执行驳回。解决方式是让编制人直接删除重编,或者走弃审,别在第一个节点上耗。

第三条,主计划抛转后事业部没收到。现象是计划员点了提交,事业部计划员的待办里没有任务。原因通常是组织类型判断错了——只有商贸类组织下的主生产计划才需要抛转,有生产实体的组织直接提交即可,反过来在非商贸组织上找抛转入口当然找不到;也有可能是抛转的六步里漏了最后的「确认提交」。解决办法是先确认编制组织类型,再看单据状态是不是停在APPROVED没到THROWN。

5.2 数据与打印类卡单

第四条,外箱标贴打出来箱号全是 1。现象是一张入库单有多个批次,打印出来的标贴条码全一样。原因是只打了第一行,手册要求逐行打印:点行号把整行拉蓝,再点「更多」右边的黑色小箭头选打印外箱标贴,多行批次依次逐行打。解决方式是把打印动作从「整单打印」改成「按行打印」,模板里的箱序号用行号加行内序号生成。

{ "template": "carton_label_80x60", "fields": { "barCode": "{{docNo}}-{{lineNo}}-{{boxSeq}}", "materialCode": "{{materialCode}}", "batchNo": "{{produceDate}}-{{seq}}", "qty": "{{boxQty}}", "projectNo": "{{projectNo}}" } }

barCode里必须带lineNo和boxSeq,只带单号必然重复;batchNo由生产日期加流水拼出来,生产日期一改批次跟着变,这也是系统里生产日期和批次联动的原因。

第五条,复制行保存不了。现象是一张入库单要录多个批次,复制第一行后改数量,保存报错。原因是复制行数量之和超过了所选主生产计划的可用数量,手册写得很明确:复制行数量必须等于或小于所选主计划可用数量,不够就保存不了。解决办法是先算清楚这张主计划还剩多少可入库量,再决定拆几行、每行多少,别边复制边试。

6. 二次开发:把手册里的隐式规则变成代码里的显式校验

这份手册最值钱的地方,是它把一堆口头约定写成了文字,比如「入库数量不能大于可用数量」「复制行数量之和不能超过主计划可用量」「同料号不同订货号是两种库存」。这些规则现在的实现方式基本靠前端提示加后端兜底,提示词还很含糊,用户只知道保存失败不知道错在哪。重做或改造时,第一件事就是把这些规则提到服务层做显式校验,并且返回结构化错误。

# 入库保存前的显式校验:替代手册里"不能大于可用数量"的口头约定 def validate_inbound_qty(doc, line): avail = get_available_qty(line.mps_id) # 主计划剩余可入库量 used = sum(l.qty for l in doc.lines if l.mps_id == line.mps_id) if line.qty <= 0: raise BizError("E1001", f"行{line.no} 数量必须大于 0") if used > avail: raise BizError( "E1002", f"行{line.no} 超出可用量:可入库 {avail},本单已占用 {used}", detail={"mpsId": line.mps_id, "avail": avail, "used": used}, ) return True

关键是detail这一段。老系统只返回「保存失败」,运维得去数据库里翻主计划余量;带上mpsId、avail、used三个值,前端就能直接在行上标红并显示差额,用户自己就能改对。同样的思路可以用在抛转校验、复制行校验、批次拆分校验上,一套错误码配一份错误文案表,比散落在各 Service 里的字符串好维护得多。

第二个改造点是批次与条码。生产日期改批次联动、外箱标贴按行打印,这两条现在耦合在页面逻辑里,一旦有移动端扫码枪接入就得重写。把「入库单行 → 批次 → 箱」拆成三层数据结构,条码只承载唯一键,展示信息全部后端拼装,打印端和扫码端就都能复用。

最后一个建议是别急着推翻审批链。手册里国内国际两条链、商贸与非商贸两种提交方式,看着乱,其实是组织架构的真实映射,重构时先把它配置化成「组织类型 + 单据类型 → 审批链」的映射表,跑一段时间对完账再动代码。

这套手册我前后翻过三遍,第一遍当教程看,第二遍照着排查工单,第三遍才是拿着它去对字段和状态。教训是第一次接手时偷懒,觉得流程图上箭头连起来就懂了,结果上线第一个月就被「同料号不同订货号」坑了一次,库存对了两天才对平。从那以后我每次碰这类老系统,都先把状态机和字段来源表抄一遍贴在显示器边上,跑通一张单再动第二张。希望帮到你。

本文还有配套的精品资源,点击获取