简介:《WMS仓库管理系统需求规格说明书》是面向仓库管理系统设计、开发、测试与维护人员的正式需求文档,用于明确系统功能边界、数据定义与业务流转规则。文档首先定义仓库管理员、库存管理员、供应商、客户等角色特征,随后从基础信息入手,完整覆盖单位组织结构、库房货位、存货人员、托盘产线、供应商、委外商及客户档案,并延伸至条码标签设计与终端设备管理;在业务层面,重点分析原料收货、原料入库等流程,为系统开发提供了可落地的需求依据。资源以单个doc文件形式打包,压缩包大小约4.41MB,已有250人学习参考,适合作为仓库管理系统需求分析、概要设计、测试用例编写及项目验收的参考文档,尤其适合处于方案规划或系统建设初期的团队使用。
1. 需求规格说明书在 WMS 项目里到底管什么用
WMS 项目做得越久越会发现,一张上架策略的算法图远不如主数据建模和标签打印环节的细节更能决定项目成败。这份 55 页的《wms仓库管理系统需求规格说明书》正好把仓库管理系统最容易被忽略的三块骨架钉死了:原料库、成品库、不合格品库、模具工装库四类库房的仓储物流管理边界,收料员、仓管员、检验员、发货员、课长、经理的多角色权限模型,以及从 ASN 收货、报检、批属性登记到入库上架的全链路单据流。新人读它看流程,能快速建立对 WMS 业务范围的完整认知;老手读它看规则,能直接提炼出实施时需要的字段设计和状态迁移条件。这份文档适用于系统设计阶段的输入以及验收时的依据,做 WMS 产品、实施、开发、测试的人都能在里面找到和自己相关的部分。
2. 主数据建模与储位编码策略
2.1 组织隔离决定主数据字段怎么加
文档的“单位组织结构”章节给出了一个容易被跳过的关键设计:基于数据权限的角度进行隔离。总部的人对系统所有数据都有查看权限,工厂与工厂之间的数据隔离,工厂内仓库可以独立针对工厂的人授权。这三句话直接决定了主数据表结构必须携带组织维度。
落地时最常见的做法是给每一张主数据表增加factory_id和warehouse_id两个归属字段。前者是数据行所属的工厂,后者是数据行所属的仓库。总部角色在查询时不做工厂过滤,工厂角色查询时强制带factory_id条件,工厂内仓库角色再加一层warehouse_id过滤。这样在应用层写一个统一的数据权限拦截器,比在每一个 SQL 里手工拼接条件要可靠得多。
有一个反直觉的点值得注意:不要把所有工厂的存货档案、货位档案放在一个大池子里,然后靠WHERE factory_id = ?过滤。虽然这样也能工作,但随着仓库数量增加,货位编码、托盘编码的全局唯一性校验会变成性能瓶颈和逻辑漏洞。更稳妥的方式是在表结构上就用复合主键或者复合唯一索引把factory_id钉死。
2.2 库房-库区-货位三级储位模型
文档里对储位模型的定义很明确:库房到库区到货位,库区是逻辑分割主要方便管理,货位才是实际的。货位档案信息包括货位编码(条码)、货位名称、所属库房、最大体积、最大重量、备注信息。其中隐藏了一条硬规则:货位条码系统内全局唯一。
全局唯一意味着货位编码不能只在单个库房内编号。实际项目里常用的编码规则是“仓库编码 + 库区编码 + 巷道 + 排 + 列 + 层”,例如CK01-A-01-02-03-01表示 1 号仓库、A 库区、01 巷道、02 排、03 列、01 层。如果仓库编码已经全局唯一,那么基于仓库编码拼接出来的货位编码自然也是全局唯一的。重型货架场景下,文档提到货位标签统一粘贴在立柱上进行扫描,这是现场经验,立柱比每个货位单独贴标更容易维护,扫描时也不会被货物遮挡。
建表语句可以这样写:
CREATE TABLE wms_location ( location_id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '货位ID', location_code VARCHAR(32) NOT NULL COMMENT '货位编码,全局唯一', location_name VARCHAR(64) NOT NULL COMMENT '货位名称', warehouse_id BIGINT NOT NULL COMMENT '所属库房', zone_code VARCHAR(16) NOT NULL COMMENT '库区编码', max_volume DECIMAL(12,3) DEFAULT NULL COMMENT '最大体积(m³)', max_weight DECIMAL(12,3) DEFAULT NULL COMMENT '最大重量(kg)', status TINYINT DEFAULT 1 COMMENT '1启用 0停用', factory_id BIGINT NOT NULL COMMENT '工厂ID,数据隔离用', UNIQUE KEY uk_location_code (location_code), KEY idx_warehouse (warehouse_id, zone_code) ) COMMENT='货位档案';货位编码的UNIQUE KEY是全局唯一约束的兜底。即使上层代码拼错了编码规则,数据库也会拦住重复数据。库区字段单独拎出来是因为文档明确库区是逻辑分割,后续按库区做盘点、按库区做统计报表都会用到这个维度。
2.3 存货档案字段与批次序列号开关
文档列出的存货档案字段包括:存货编码(唯一)、存货名称、存货代码、计量单位、安全库存、最高库存、最低库存、积压标准、备注、单个存货重量、单个存货价格(ERP 同步)、数量/件数、是否保质期管理、是否批次管理、是否序列号管理信息。
其中“数量/件数”这个字段很容易被误解。文档里举例“如设置 100 则 100 个存货为 1 件”,这是统计单位换算,不是包装单位。仓库里可能同时存在“箱”和“托”两个包装层级,但需求文档里的“件”是用来做存货物动量统计分析的虚拟单位。实施时要注意这个换算值会影响报表模块的计算口径,改动它的权限应该收归到系统管理员,不能让仓库普通操作员随意修改。建表语句如下:
CREATE TABLE wms_sku ( sku_id BIGINT PRIMARY KEY COMMENT '存货编码,ERP同步', sku_name VARCHAR(64) NOT NULL COMMENT '存货名称', sku_code VARCHAR(32) DEFAULT NULL COMMENT '存货代码', unit VARCHAR(16) NOT NULL COMMENT '计量单位', safe_stock DECIMAL(18,3) DEFAULT 0 COMMENT '安全库存', max_stock DECIMAL(18,3) DEFAULT NULL COMMENT '最高库存', min_stock DECIMAL(18,3) DEFAULT NULL COMMENT '最低库存', piece_qty INT DEFAULT 1 COMMENT '数量/件数换算,100表示100个为1件', single_weight DECIMAL(10,4) DEFAULT NULL COMMENT '单个存货重量(kg),统计分析用', is_batch TINYINT DEFAULT 0 COMMENT '是否批次管理 1是0否', is_sn TINYINT DEFAULT 0 COMMENT '是否序列号管理 1是0否', is_expiry TINYINT DEFAULT 0 COMMENT '是否保质期管理 1是0否', factory_id BIGINT NOT NULL COMMENT '工厂ID', UNIQUE KEY uk_sku_factory (factory_id, sku_id) ) COMMENT='存货档案主数据';is_batch、is_sn、is_expiry三个开关是 WMS 的差异化功能开关。开启批次管理的存货,在收货时必须录入批号,库存表里每一行都要带batch_no字段;开启序列号管理的存货,收货时要逐个扫描序列号,库存表要按序列号维度存储;开启保质期管理的存货,需要额外登记生产日期和失效日期。这三个开关直接影响 PDA 收货界面、盘点界面和出库界面的字段布局,需求阶段必须明确哪些 SKU 开了哪些开关,实施阶段才能排对开发量。
3. 条码标签体系与打印通道选型
3.1 八类标签的规格对照
文档“条码标签设计”章节给出了非常具体的标签规格和数据内容,这些细节在实际项目中往往被忽略,却恰恰是 WMS 能否在仓库里顺畅跑起来的关键。把文档里的标签信息整理成下表:
| 标签类型 | 尺寸 | 材质 | 打印环节 | 打印机类型 |
|---|---|---|---|---|
| 待检卡 | 80×190 | 不可粘贴 | 收货核对完成、报检前 | 普通打印机 |
| 产品标示卡(不可贴) | 80×190 | 不可粘贴 | 半成品下线检验合格后 | 普通打印机 |
| 产品标示卡(可贴) | 20×60 | 可粘贴 | 收货检验合格后 | 条码打印机 |
| 成品标签 | 50×60 | 可粘贴 | 成品下线时 | 普通打印机 |
| 资产标签 | 待定 | 待定 | PDA 采集器测试后定 | 条码打印机 |
| 托盘标签 | 35×93 | 可粘贴、防撕、防水、耐磨 | 系统随时打印 | 条码打印机 |
| 货位标签 | 35×93 | 可粘贴、防撕、防水、耐磨 | 系统随时打印 | 条码打印机 |
| 发货标签 | 20×60 | 可粘贴 | 发货员按发货单打印 | 条码打印机 |
80×190 这种大尺寸标签承载的信息量大,包含存货编码、规格型号、批号、检验结论、检验员等字段,适合作为随货单据卡;20×60 的小尺寸标签适合贴在单个包装上,内容精简为存货名称、代码、数量、批号。这种“大标签随单据、小标签贴实物”的做法,在制造业仓库里是兼顾信息完整性和贴标效率的通用方案。
3.2 普通打印机与条码打印机的分工
文档里同一个“产品标示卡”出现了两种规格:80×190 不可粘贴版本和 20×60 可粘贴版本。前者的打印环节是“生产班组在半成品下线检验合格后打印,由普通打印机打印”,后者的打印环节是“收货检验合格后进行打印,条码标签打印机”。这背后的逻辑是两条独立的打印通道:普通打印机输出的是纸张单据卡,跟着流转单据走;条码打印机输出的是不干胶标签,贴在实物包装上。
打印通道的选型会影响系统设计。普通打印机通常部署在办公室或车间固定工位,通过 Windows 打印服务共享;条码打印机可能部署在收货理货区、发货月台,同样走网络打印。系统里需要维护打印机设备档案,把打印任务路由到正确的打印机。终端设备管理章节提到的“管理所有 PDA 手持设备、记录设备信息:设备名称、设备编号、备注信息。只能在系统中的设备才能接入 WMS 进行操作”,打印机也应该纳入同样的设备管理体系,否则换了打印机 IP 变了,标签格式就乱了。
3.3 打印时机的状态依赖
打印任务不能是独立的“打印按钮”操作,而应该是单据状态的副作用。以收货流程为例,待检卡只能在“收货核对完成、报检前”这个状态区间打印;产品标示卡只能在“质检合格”之后打印;发货标签只能在“发货单已生成”之后打印。这个约束可以用状态映射表来表达:
PRINT_RULES = { "待检卡": {"required_status": "COUNTERED", "printer": "laser", "size": "80x190"}, "产品标示卡": {"required_status": "INSPECTED_OK", "printer": "label", "size": "20x60"}, "成品标签": {"required_status": "PRODUCED", "printer": "laser", "size": "50x60"}, "托盘标签": {"required_status": "PALLET_CREATED", "printer": "label", "size": "35x93"}, "货位标签": {"required_status": "LOCATION_CREATED", "printer": "label", "size": "35x93"}, } def can_print(tag_type: str, order_status: str) -> bool: rule = PRINT_RULES.get(tag_type) if not rule: return False return order_status == rule["required_status"]实现时在打印接口里先校验状态,状态不满足直接拒绝打印并返回当前状态码,而不是让前端把打印按钮置灰。前端置灰很容易被绕过,后端校验才是硬约束。托盘标签和货位标签的打印时机是“系统随意打印”,这类基础数据标签的补打功能要放在档案维护界面,跟业务单据打印通道分开,避免把流程打印和补打混在一起。
4. 原料收货链路与质检状态流转
4.1 四类收货流程的差异对照
原料收货分为采购收货、委外收货、生产收货、调拨收货四大类。文档对每一类的业务描述和需求分析都给出了流程,但把它们放在一起对比,才能看出系统设计需要区分哪些边界条件:
| 对比维度 | 采购 ASN 收货 | 委外收货 | 生产收货 | 调拨收货 |
|---|---|---|---|---|
| 单据来源 | ERP 同步 ASN 到货单 | 纸质委外送货单,WMS 录入 | 产成品收货通知 | 调拨入库单通知 |
| 收货方式 | PDA 扫描 ASN 单条码核对 | 收料员核对纸质单+实物 | PDA 扫描产品标示卡 | PDA 扫描产品标示卡 |
| 报检触发 | 收货员在 WMS 中来料报检 | 录入委外到货后提交报检 | 产线下线流程已报检 | 已在来源仓完成质检 |
| 数量异常 | 与 ASN 数量不符整单拒收 | 与送货员核对修改送货单 | 按实际数量收货+预警 | 按实际数量收货+预警 |
| 特殊控制 | 艺达工厂由采购部业务员报检 | 生管部业务员在 ERP 登记 | 可补打产品标示卡、组托 | 可补打产品标示卡、组托 |
采购收货和委外收货对数量异常的处置逻辑完全不同。采购收货场景里“单据与实物不符退还采购部门 ASN 单据进行拒收”,是整单拒收;生产收货和调拨收货场景里“按照实际数量进行收货系统进行预警处理记录异常信息”,是差额收货加预警。这个差异必须在系统参数里做成可配置的收货策略,不能写死在代码里。原因很简单:采购场景面对的是外部供应商,整单拒收是商务约束;生产场景面对的是内部产线,差额收货是为了保证生产连续性,差值可以通过后续补单或异常处理流程消化。
4.2 单据状态机与 ERP 回写
文档多处提到“系统同步 ERP 中的 ASN 到货单信息”“系统回写 ERP 完成 ASN 到货单收货”,这说明 WMS 与用友 ERP 之间存在双向集成。WMS 侧必须维护一套独立的单据状态机,每一步操作都对应明确的状态迁移:
ASN_STATUS = { "SYNCED": "已同步待收货", "COUNTERED": "已核对数量", "INSPECTING": "质检中", "PASSED": "质检合格待入库", "REJECTED": "整单拒收", "STORED": "已上架入库", "ERP_WRITTEN": "已回写ERP", } TRANSITIONS = { "SYNCED": ["COUNTERED", "REJECTED"], "COUNTERED": ["INSPECTING", "REJECTED"], "INSPECTING": ["PASSED", "REJECTED"], "PASSED": ["STORED"], "STORED": ["ERP_WRITTEN"], "REJECTED": [], # 终态 "ERP_WRITTEN": [], # 终态 } def can_transition(current: str, target: str) -> bool: return target in TRANSITIONS.get(current, [])状态机里有一个值得注意的点:COUNTERED可以直接迁到REJECTED,因为收货核对发现数量不符时,直接拒收,不需要进入质检环节。而INSPECTING到REJECTED对应的是质检不合格场景,文档写的是“不合格品全部拒收退货”。这一条业务规则在实施时容易漏掉,如果质检不合格还允许部分入库,就和文档定义的“全部拒收”冲突了。
ERP 回写操作放在STORED之后,即上架完成才回写。回写接口要支持幂等,重复调用不能生成重复的 ERP 入库单。常见做法是回写前先查 ERP 侧是否已存在对应的 WMS 单据号,存在则跳过写入直接返回成功。
4.3 批属性登记与保质期管理的耦合
文档在采购 ASN 单收货的需求分析里明确写了:“对于需要保质期管理的需要进行批属性登记”。批属性登记包含生产日期、失效日期、供应商批次号、收货日期等字段。只开批次管理不开保质期管理的存货,批属性只需登记批号;开了保质期管理的存货,必须额外维护失效日期。
这里有一个实施中常见的坑:失效日期是从 ERP 主数据同步保质期天数,然后收货时按“生产日期 + 保质期天数”自动计算。这个逻辑本身没问题,但跨天收货场景下,同一批货在 23:50 收货和次日 00:10 收货,计算出来的失效日期可能差一天。稳妥做法是收货时自动计算失效日期,但允许仓管员在 PDA 上手动修正,同时记录修正日志;库存报表按失效日期做近效期预警,超期库存要能追溯到批属性登记的原始数据。
不合格品在质检完成后要移入不合格品库,文档中“原料库、成品库、不合格品仓库”并列出现,说明系统里不合格品库是独立库房。这里的库存转移动作和质检结论绑定,质检合格库存从待检状态转为可用,质检不合格库存转入不合格品库并触发退货流程。整个链路的状态流转都要在数据库事务里完成,避免出现质检结论已更新但库存状态没跟着变的中间态。
5. 从需求文档到实施蓝图的核对技巧
5.1 把流程描述翻译成状态机矩阵
拿到一份需求规格说明书,逐字读业务描述效率太低,我更习惯先把所有动词提取出来,翻译成状态迁移候选集,再和文档中描述的流程做比对。比如“收料员进行收货,核对 ASN 单”“收料员针对到货单进行抽样并手写待检卡”“检验合格后收料员把抽检样件返回原包装”“将合格原料与报检单提交给相应的仓管员”,提取出的状态就是“已核对”“已报检”“已检验”“已入库”。
把状态迁移候选集和文档流程图比对之后,用脚本找出没有定义的路径,这些路径就是需求空白点:
def find_undefined_transitions(defined: dict, statuses: list): defined_set = set() for src, targets in defined.items(): for tgt in targets: defined_set.add((src, tgt)) all_possible = set() for src in statuses: for tgt in statuses: if src != tgt: all_possible.add((src, tgt)) return all_possible - defined_set # 传入文档中定义的状态机和全量状态列表,输出未覆盖的迁移路径 undefined = find_undefined_transitions(TRANSITIONS, list(ASN_STATUS.keys())) print(undefined)对这份文档的收货模块跑一遍,通常会发现“质检中”直接到“已上架入库”没有定义,如果实施时遗漏这条路径,质检员在 PDA 上就可能无法为免检物料直接做入库确认。这类路径要么补充到状态机里,要么在需求评审时明确提出让业务方确认。
5.2 打印环节的边界条件核对
标签打印环节的核对重点是“状态依赖”和“补打权限”两个维度。待检卡只能在收货核对完成后打印,质检合格后不能补打待检卡,因为质检结论已经出来再补打待检卡会误导操作员认为该批货物还在待检状态。产品标示卡允许补打,但补打记录里要保留原始打印人和补打人两个字段,便于追溯。
资产业务模块的核对重点不同,模具、工装、设备、刀具四类资产各自有验收、借出、归还、维修、变更、保养、盘点、报废八个动作,每个动作都要记录操作人、时间和资产状态。文档里资产标签的规格写着“PDA 采集器与标签测试后待定”,说明资产标签的条码制式和粘贴位置要在现场测试后确定,实施计划里要预留这个测试环节的时间,不要去猜测最终方案。对照文档把这条链路用状态机校验脚本完整跑一遍,每个未定义的中间状态,就是下一轮需求评审会议的第一个议题。
本文还有配套的精品资源,点击获取