从MRP到ERP:BOM展开、低层码与能力校验工程解析

从MRP到ERP:BOM展开、低层码与能力校验工程解析 简介「ERP基础理论(pdf版183页).pdf」是一份系统梳理企业资源计划知识脉络的理论讲义适合信息管理、工商管理、工业工程等专业学生以及刚接触ERP系统的实施顾问、制造业管理者用作入门与复习参考。文档共183页压缩包内仅含1个PDF文件大小约2.73MB单文件结构便于直接翻阅、检索与打印。内容从20世纪60年代的库存订货点理论与基本MRP讲起依次延伸到闭环MRP、MRP-II再到90年代Gartner提出ERP概念及ERP II的发展趋势完整呈现管理思想演进的动因同时配有MRP逻辑流程、闭环MRP计算流程、MRP-II逻辑流程图串联主生产计划、物料需求计划、能力需求计划、采购与车间作业、成本会计等模块并涉及供应链中物流、资金流、信息流的集成管理及ERP实施议题。目前已有118人学习可作为理解ERP原理与实施框架的参考。1. 从库存订货点到ERP四代计划逻辑的演进一份183页的《ERP基础理论》从库存订货点一路讲到ERP II时间跨度四十年。很多人翻这类教材会觉得像在读管理史其实真正的信息量压在两条线上一条是需求怎么分层另一条是能力怎么约束。订货点法用安全库存给不确定的需求和提前期做缓冲成立的前提是需求相对独立、消耗平稳一旦进入产品结构笔帽、笔芯、笔油墨的需求全部由成品圆珠笔倒推出来再去算订货点就变成了自我循环。约瑟夫·奥利佛把需求拆成独立需求与相关需求MRP才算有了立足点后来的闭环MRP补上能力校验MRP-II把物流、信息流、资金流并到一张图上ERP再把范围推到供应链。这份材料适合两类人准备接手ERP二次开发、数据对接的工程师以及要给实施顾问做需求交底的产品经理。后面几章按它原本的脉络把每一代逻辑落到表结构、算法和参数取值上。2. 基本MRP的运算闭环BOM展开、独立需求与相关需求MRP这一层是整套ERP的地基地基里最关键的不是公式而是「谁的需求是算出来的、谁的需求是给出来的」。这条边界划错后面的净需求、批量、提前期全部错位。这一章按教材1.1节的顺序把产品结构、库存信息、主生产计划三份输入拼成一次完整的运算。2.1 独立需求与相关需求的分界独立需求来自企业外部只能预测或接单成品圆珠笔、备品备件的需求属于这一类相关需求由产品结构推导笔芯头、笔芯杆、笔油墨的用量完全由圆珠笔的订单量乘单位用量得出不需要单独预测。订货点法的问题在于它把两类需求一视同仁地塞进「消耗速度 × 提前期 安全库存」这个模型里而相关需求的消耗是脉冲式的——成品下线那一刻几十种零件的需求同时跳变平均值毫无意义。教科书里那张「库存量—时间」曲线画的是锯齿现实里锯齿的间距由主生产计划决定不由历史消耗决定。所以MRP的输入必须包含MPS而不是拿销售预测直接冲减库存。2.1.1 圆珠笔结构树给出的三个结论教材用圆珠笔举例笔芯、笔筒、笔油墨、笔芯头、笔芯杆、笔帽挂在同一棵树下。这棵树传递三条信息第一同一物料可能出现在多个父项下通用件必须按总需求汇总后再扣库存第二层级深度不同计算顺序必须自下而上否则上层还在变、下层已经算完第三层级不是固定的工程变更会让某个零件从二级掉到三级低层码必须动态维护。很多ERP数据对接项目出问题就出在低层码没随BOM变更重算。2.2 低层码与MRP的四个输入低层码Low Level Code是物料在全部BOM中出现的最深层次。计算净需求时按低层码从0开始逐层下推保证一个物料只被计算一次且是在它的所有父项需求都已汇总之后。这是MRP能在线性时间内跑完几万行物料的关键。输入来源模块关键字段缺失后果主生产计划MPS销售/计划物料、需求日期、数量毛需求无从生成物料清单BOM工程父项、子项、单位用量、损耗率相关需求断裂库存信息仓储现有量、已分配量、在途量、安全库存净需求虚高或虚低物料主数据基础数据提前期、批量规则、低层码计划订单日期算不准提前期决定了计划订单的下达日期需求日期减去提前期才能得到「什么时候该下单」。采购件用采购提前期自制件用制造提前期两者不能混用同一个字段。2.3 用Python写一遍净需求与批量推断把公式写出来只要几行难的是把批量规则、安全库存、已分配量都带进去。下面这段代码处理单层净需求返回计划接收量与期末可用量。# 单层MRP净需求推算 def net_requirement(gross, on_hand, allocated, safety, lot_size, lead_time0): gross 毛需求MPS或上层展开结果 on_hand 现有库存 allocated 已分配量已发料未出库、已承诺订单 safety 安全库存低于它要补货 lot_size 固定批量按倍数向上取整 lead_time 提前期天只影响计划下达日期 available on_hand - allocated # 可用库存才是真能用的 shortage gross safety - available # 缺口 毛需求 安全库存 - 可用量 if shortage 0: return 0, available - gross # 不用补直接结转 # 固定批量向上取整(缺口 批量 - 1) // 批量 * 批量 planned ((shortage lot_size - 1) // lot_size) * lot_size ending available planned - gross # 本期期末可用 return planned, ending逻辑上先算可用量再算缺口顺序不能颠倒。已分配量如果不扣计划订单会偏少产线上就会出现「系统里说有货、仓库里拿不出」。批量取整用整除比用math.ceil更稳浮点误差小一些如果批量规则是「经济订货批量」或「按需批量」把lot_size传1等同按需。BOM展开则用递归顺带打印层级方便核对def explode(bom, item, qty, level0): # bom: {圆珠笔: [(笔芯,1),(笔筒,1),(笔帽,1)], ...} for child, per in bom.get(item, []): need qty * per print(f{ * level}{child:10}{need:10.2f}) if child in bom: # 还有下层就继续下钻 explode(bom, child, need, level 1) bom { 圆珠笔: [(笔芯, 1), (笔筒, 1), (笔帽, 1)], 笔芯: [(笔油墨, 1), (笔芯头, 1), (笔芯杆, 1)], } explode(bom, 圆珠笔, 1000)递归写法直观但生产环境里几万行BOM会爆栈常见做法是先按低层码排序、再做自底向上的循环或者用一次性的公用表表达式CTE在数据库里展开。2.4 落到PostgreSQL的表结构教材里画的是逻辑流程图工程上要变成三张能跑的表。下面是最小可用版本。CREATE TABLE item_master ( item_code VARCHAR(32) PRIMARY KEY, item_name VARCHAR(64) NOT NULL, low_level SMALLINT DEFAULT 0, -- 低层码BOM变更后重算 lead_time INT DEFAULT 0, -- 提前期天数 lot_size DECIMAL(18,4) DEFAULT 1, -- 固定批量 safety_stock DECIMAL(18,4) DEFAULT 0, source_type VARCHAR(8) DEFAULT BUY -- BUY自制/采购 ); CREATE TABLE mps ( item_code VARCHAR(32) NOT NULL, due_date DATE NOT NULL, qty DECIMAL(18,4) NOT NULL, PRIMARY KEY (item_code, due_date) ); CREATE TABLE inventory ( item_code VARCHAR(32) PRIMARY KEY, on_hand DECIMAL(18,4) DEFAULT 0, allocated DECIMAL(18,4) DEFAULT 0 );low_level放在物料主数据上而不是BOM表上是因为一次展开要反复读它放主数据能进缓存。mps的主键用「物料需求日期」而不是自增ID是为了让重复导入可以ON CONFLICT DO UPDATE避免计划数据被灌重。2.5 参数说明与典型误用把安全库存设成「一个月用量」是最常见的做法也是最容易掩盖问题的做法。安全库存应当覆盖提前期的需求波动和供应波动公式是Z × √(提前期) × 需求标准差Z取1.65对应95%服务水平。提前期填成供应商承诺的最短天数实际到货一延迟整个计划就整体后移。提示低层码在BOM新增、删除、改挂父项之后必须全量重算增量维护的成本通常高于全量重算。另一类误用是把在途采购量当作可用库存直接抵扣净需求。在途量应该按预计到货日进入对应时区的供给而不是全部塞进第一期否则第一期净需求为负、后面又集中缺料。3. 闭环MRP到MRP-II能力校验、三流合一与成本卷积教材1.2节把闭环MRP画成一张带回环的图MPS和MRP算完之后要过RCCP和CRP两道校验不可行就回头改计划或改能力。这一步是MRP从「算得出来」变成「干得出来」的分水岭。1.3节的MRP-II在此基础上叠加了决策层、计划层、执行层三层结构把资金流和成本会计并进来。3.1 闭环MRP的可行性回路闭环的「闭」体现在两条回路上一条是能力不足时修改主生产计划另一条是能力过剩时调整能力数据加班、外协、增加班次。教材那张图里有三个YN判断点实际工程中对应三次迭代上限通常设3到5轮超过就转人工干预否则运算时间不可控。投入产出控制I/O是闭环里最容易被忽略的模块。它按工作中心记录计划投入、实际投入、计划产出、实际产出四个数字一对比就能看出瓶颈在哪个环节卡住。3.2 RCCP与CRP粗能力与细能力的粒度差别两者都叫能力计划但粒度差一个数量级混用会导致算出来的负荷对不上。维度RCCP粗能力CRP能力需求计划对象关键工作中心全部工作中心数据来源MPSMRP计划订单时间粒度周或月日或周计算方式历史负荷比例、资源清单工艺路线 × 工时定额用途判断主生产计划是否可行生成车间作业排程粗能力的价值在于快。MPS刚出来、MRP还没跑先用资源清单乘以负荷系数估一遍几分钟就能给出「接不接这张单」的判断。细能力要等MRP展开完才准代价是运算量大。3.3 MRP-II的三层结构与三流合一决策层放经营规划、销售规划计划层放主生产计划、粗能力计划、物料需求计划、能力需求计划执行层放采购作业、车间作业、成本会计、业绩评价。三层之间靠「可行/不可行」的反馈连接。三流合一指的是物流、信息流、资金流共用一套事务数据。采购收货这一个动作同时更新库存数量物流、采购订单状态信息流、应付暂估资金流。这也是ERP和单纯的进销存最本质的区别——后者只记数量不记钱。3.4 用SQL做一次工作中心负荷测算把MPS按工艺路线的工序偏移量摊到周再和可用产能对比就得到一张负荷率表。下面这段是PostgreSQL写法。-- 各工作中心未来8周的负荷率 SELECT a.work_center, a.week_start, a.available_hours, COALESCE(l.load_hours, 0) AS load_hours, ROUND(COALESCE(l.load_hours, 0) / NULLIF(a.available_hours,0), 3) AS load_rate FROM capacity_avail a LEFT JOIN ( SELECT op.work_center, DATE_TRUNC(week, m.due_date - (op.offset_days || day)::interval)::date AS week_start, SUM(op.run_time * m.qty / 60.0) AS load_hours -- 单件工时按分钟存转小时 FROM mps m JOIN routing_op op ON op.item_code m.item_code GROUP BY 1, 2 ) l ON l.work_center a.work_center AND l.week_start a.week_start ORDER BY a.work_center, a.week_start;offset_days是工序相对完工日的倒排偏移倒排能让计划跟着需求日期走。run_time按分钟存储是行业惯例很多系统按小时存对接时先对齐单位再写SQL。NULLIF防除零load_rate 1就是超载1.0到1.1之间通常容忍超过1.2必须调整计划或增加班次。注意DATE_TRUNC的周起点随数据库区域设置变化PostgreSQL默认周一某些环境是周日跨系统对账前先确认。4. ERP实施主数据、参数开关与上线顺序教材里ERP实施那部分篇幅不长但落到项目上八成的问题都出在主数据和参数上。这一章把实施过程拆成可检查的动作。4.1 主数据先行四张基础表物料主数据、BOM、工艺路线、工作中心是ERP的四大主数据任何一张不干净后面全部失真。清理顺序建议是物料 → 工作中心 → 工艺路线 → BOM因为BOM里的子项必须先在物料主数据里存在。具体动作先给物料编码定规则大类小类流水禁止「临时料」「待定」这类名称进系统再做单位换算表采购按公斤、领用按个的物料必须有换算系数最后做BOM的版本管理工程变更走ECN流程旧版本设失效日期而不是直接删除否则历史工单的成本回算会断。# 导入前先做一次重复编码检查输出重复项到文件 psql -h db -U erp -d erp -c \copy ( SELECT item_code, COUNT(*) AS cnt FROM item_master GROUP BY item_code HAVING COUNT(*) 1 ) TO /tmp/dup_item.csv WITH CSV HEADER\copy是客户端命令比服务端COPY在权限受限的环境更好用导出的文件落在执行命令的机器上。4.2 提前期、批量与安全库存的取值方法这三类参数没有标准答案但有取值逻辑照下表逐项落实能挡掉大部分低级错误。参数取值依据常见误用采购提前期近12个月实际到货天数P85分位直接填合同最短交期制造提前期排队准备加工等待搬运只算加工工时固定批量供应商最小起订量/包装倍数一律填1订单碎成几千张安全库存Z × √提前期 × 需求标准差拍脑袋填一个月用量损耗率近3个月实际领用/理论用量忽略不计提前期取P85而不是平均值是因为计划要留出足够的把握度取最大值又会让库存周转变差。分批期的概念也值得引入同一物料在连续几个工作日内的需求合并成一张计划订单能显著减少订单数量。4.3 上线顺序与并行运行的判定切分上线范围按「数据独立性」而不是「模块大小」。采购、库存、应付通常第一批上因为它们共享供应商和物料主数据生产、车间、成本第二批总账和报表最后。并行运行期间每天要做三件事核对库存数量差异清单、核对未结采购订单差异、核对工单在制数量。判定能否停掉手工账看两条硬指标连续两个结账周期库存差异率低于0.5%以及成本卷积结果与手工核算差异在可接受范围内。提示并行期拖得越久两套账的数据越难收敛一般控制在两个完整结账周期内。4.4 上线后最常见的六个坑第一未结工单挂在系统里不关导致在制库存虚高第二退货没有走退货单直接做负向领料成本冲销错科目第三BOM变更没有设生效日期历史工单被新BOM重算第四工作中心可用产能没有按月维护日历负荷率永远偏高第五批次/序列号管理开启后没有配套的拣货规则仓库靠记忆发货第六权限给到「全部工厂」一个误操作能改掉全集团的价格主数据。5. 把183页PDF做成可检索知识库解析、结构化与交叉校验这类教材的价值在于逻辑图而逻辑图恰恰是最难检索的部分——pdftotext抽出来的流程图文字常常是散的。如果团队里要把这本183页的材料当成新人培训底稿先把它结构化比反复翻页高效得多。5.1 解析前的元信息核对先确认文件本身没问题再动手抽文本。pdfinfo ERP基础理论(pdf版183页).pdf | grep -E Pages|Page size|Producer pdftotext -layout -f 1 -l 30 ERP基础理论(pdf版183页).pdf erp_ch1.txtpdfinfo的Pages应该和标题里的183页对得上对不上说明文件被截断或加了封面。pdftotext -layout保留原始列位置对两栏排版效果好但对流程图页会抽出交错的行这时候换pdfplumber按坐标抽。5.2 按章节切分并抽取关键词行教材的章节标题形如「1.1 基本MRP」用它做切分锚点最稳。import re, pdfplumber HEAD re.compile(r^\s*(\d\.\d)\s(\S.*)$) # 匹配 1.1 基本MRP def split_sections(path, start20, end60): cur, buf None, [] with pdfplumber.open(path) as pdf: for page in pdf.pages[start:end]: text page.extract_text(x_tolerance2, y_tolerance3) or for line in text.splitlines(): m HEAD.match(line) if m: if cur: yield cur, buf cur, buf (m.group(1), m.group(2).strip()), [] elif cur: buf.append(line.strip()) if cur: yield cur, buf for sec, lines in split_sections(ERP基础理论(pdf版183页).pdf): hits [l for l in lines if any(k in l for k in (提前期, 批量, 低层码, 能力))] print(sec, len(lines), 行, 命中, len(hits))x_tolerance和y_tolerance控制字符聚合成词、成行的横向和纵向距离阈值默认值在字距较大的标题上容易把一行拆成两三行调到2和3通常就稳了。切分锚点用正则而不是字符串匹配是为了避开正文里出现的「1.1」这种编号。5.3 交叉校验让解析结果对得上原文抽完之后不要直接入库做两轮校验。第一轮是行数校验逐节统计抽出的行数和关键词命中数某节行数为0说明切分锚点漏了第二轮是页码回填把每节的起止页记下来方便人肉回查。遇到流程图页比如闭环MRP那张带回环的图文本抽取必然丢失连线关系。可行的做法是把图页单独导出成图片用extract_tables加text策略先试抽不出就退回人工标注把「MPS → MRP → RCCP/CRP → 可行/不可行」这样的路径写成有向边的清单与后面的章节文字互相印证。校验的重点始终是同一件事抽出来的文字能不能和PDF里那句原话逐字对上对不上就调容差参数别急着改内容。本文还有配套的精品资源点击获取