如何开发一套ERP(离散制造-MTO)系统(附架构图+流程图+代码参考)

简介: 本文介绍了面向离散制造-MTO(按订单生产)模式的ERP系统设计与实现方法。内容涵盖ERP系统定义、总体架构设计、主要功能模块解析、关键业务流程(订单到交付、BOM展开、MRP逻辑、排产等)、开发技巧(DDD、微服务、事件驱动)、参考代码示例、部署上线注意事项及实施效果评估。旨在帮助企业与开发团队构建高效、灵活、可扩展的ERP系统,提升订单交付能力与客户满意度。

离散制造(Discrete Manufacturing)里常见的生产模式有MTS(Make To Stock)和MTO(Make To Order)。MTO强调按订单生产、产品往往有较高的定制化和多变的BOM。对于制造企业来说,一套贴合 MTO 特性的 ERP 系统,能把“订单 → 设计 → 物料 → 计划 → 生产 → 交付”这条链路串通起来,降低交付风险、减少呆滞物料、提高响应速度和客户满意度。本文将把如何搭建一套面向离散制造—MTO 的 ERP 系统拆成可执行的步骤,给出架构图、流程图,以及一个完整的参考代码片段,帮助企业和开发团队落地实施。


本文你将了解

  1. 什么是 ERP(离散制造 - MTO)系统?(定义与核心价值)
  2. 总体架构(含架构图)
  3. 主要功能模块详解(技术管理、客户、销售、生产、采购、库存、财务)
  4. 关键业务流程(含流程图):订单到交付、BOM展开、MRP 逻辑、排产、采购下发、完工结算
  5. 开发技巧与实现建议(DDD、微服务/模块化、消息中间件、幂等、测试)
  6. 参考代码(一个完整的大样例,包含数据库 schema、关键接口、BOM 展开与简单排产算法)
  7. 部署、运维与上线注意事项
  8. 实现效果与关键 KPI

注:本文示例所用方案模板:简道云ERP系统,给大家示例的是一些通用的功能和模块,都是支持自定义修改的,你可以根据自己的需求修改里面的功能。


1 什么是 ERP(离散制造 - MTO)系统?

简单说:ERP 是企业资源计划系统,但不同企业、不同生产模式下 ERP 的重点不同。离散制造 MTO 的特点是:

  • 以订单为驱动:生产始于客户订单,库存推迟或最小化。
  • BOM / 配套复杂:同一产品按订单可有多种配置与选配。
  • 交期敏感:需快速从订单到交付的透明化流程与协同。
  • 设计变更频繁:需要与 PLM/工程变更流程有紧密衔接。

因此,MTO ERP 要解决的主要问题是:如何在保证交期的情况下,动态展开 BOM、计算物料需求、触发采购与生产排程、并把成本和财务信息准确落地。


2 总体架构(建议)

下面用 Mermaid 给出一个高层架构图——这是一个典型的微服务/模块化设计,适配中大型制造企业的扩展需求。

graph LR

 subgraph Users

   A[销售/客服] -->|web| Frontend

   B[计划/车间] -->|web/移动| Frontend

   C[采购/仓库] -->|web| Frontend

   D[财务/管理] -->|web| Frontend

 end

 Frontend --> API_GW[API 网关]

 API_GW --> Auth[认证服务]

 API_GW --> MSales[销售服务]

 API_GW --> MCustomer[客户服务]

 API_GW --> MProd[生产服务]

 API_GW --> MPur[采购服务]

 API_GW --> MInv[库存服务]

 API_GW --> MFin[财务服务]

 API_GW --> MTech[技术管理/PLM接口]

 MProd -->|events| MQ[消息队列(RabbitMQ/Kafka)]

 MPur -->|events| MQ

 MInv -->|events| MQ

 subgraph Persistence

   DBMain[(Postgres)]

   Cache[(Redis)]

   FileStore[(对象存储)]

 end

 MSales --> DBMain

 MProd --> DBMain

 MInv --> DBMain

 MFin --> DBMain

 Auth --> DBMain

 MQ --> DBMain

 MTech --> FileStore

 subgraph Integration

   PLM[PLM/CAD]

   MES[MES/车间系统]

   ERP3P[第三方ERP/供应商门户]

 end

 MTech --> PLM

 MProd --> MES

 MPur --> ERP3P

核心组件说明:

  • API 网关 + 认证服务:统一鉴权、限流、审计、版本管理。
  • 微服务:按业务边界拆分(销售/客户/生产/采购/库存/财务/技术管理)。
  • 消息队列:用于异步事件(订单变更、采购下发、入库、完工等),保证系统解耦并提升并发处理能力。
  • 主数据库(建议 PostgreSQL) + Redis 缓存 + 对象存储(BOM 文档、CAD 图纸)。
  • 集成层:PLM、MES、供应商门户、物流系统。

3 主要功能模块详解

下面把每个模块的关键职责和实现建议写清楚,并给出典型字段/接口建议。

技术管理(MTech / PLM 接口)

职责:管理产品结构(BOM)、工艺(Routings)、物料主数据、版本与工程变更(ECO/ECN)。 要点:

  • 支持多级BOM(父子关系),BOM要支持版本控制(有效期/生效版本)。
  • 工艺路线包含工序、标准工时、首件检验、设备与技能要求。
  • 提供 REST 接口供 ERP 调用:GET /bom/{productId}?version=xxx,并能推送工程变更事件。
  • 建议把 CAD/文档存对象存储,DB 存元数据与访问地址。

客户管理

职责:客户档案、联系人、账期、信用额度、送货地址与交货条款。 要点:

  • 重点是为销售与交期评估提供快速判断:客户优先级、付款条件、历史退货率等。
  • 接口示例:GET /customers/{id},POST /customers/{id}/credit-check

销售管理

职责:订单录入、报价、合同、订单确认、交期评估(ATP/可承诺发货能力)。 要点:

  • 支持配置型销售(可基于配置规则动态生成 BOM)。
  • 与技术管理交互:若客户特殊定制,产生新的工艺或BOM版本。
  • 在订单确认时触发 MRP(对于 MTO,MRP 计算从订单需求开始)。

生产管理

职责:物料需求计算(MRP)、主生产计划(MPS)、排产(APS)、车间执行(MES 对接)、完工入库。 要点:

  • MTO 下 MRP 以订单为驱动,尽量短时滚动计划。
  • 排产需要考虑:设备能力、工序优先级、物料可用性、工装/夹具。
  • 提供车间看板、派工单、巡检/质量记录上传接口。

采购管理

职责:供应商管理、采购申请、采购订单、到货检验、供应能力协同(供需看板)。 要点:

  • 支持询价/比价、多供应商、分批到货。
  • 对关键物料支持安全库存和交期缓冲管理。
  • 对长期外协加工,应与外协订单模块集成。

库存管理

职责:库存账、批次/序列号管理、在途、占用与可用量(ATP)、仓储作业(入库/出库/调拨)。 要点:

  • MTO 常有“订单占用”场景:在生产前便对关键件进行占用或冻结。
  • 支持批次/序列号追溯,满足质量与召回要求。
  • 与采购、生产紧密联动:采购到货触发质检入库,生产完工触发入库。

财务管理

职责:应收/应付、成本核算(标准成本/实时报表)、结算、发票管理。 要点:

  • 对 MTO,按单核算成本很重要(按订单/批次计算毛利)。
  • 集成总账与固定资产模块,支持成本分摊与完工入账(WIP 处理)。

4 关键业务流程

4.1 订单 → 交付

flowchart TB

 A[客户下单] --> B[销售录入/配置]

 B --> C{是否标准BOM?}

 C -->|是| D[生成生产订单]

 C -->|否| E[派工工程/生成新BOM版本]

 D --> F[MRP:计算物料需求]

 E --> F

 F --> G{物料可用?}

 G -->|是| H[排产并下发派工]

 G -->|否| I[触发采购/外协]

 I --> J[供应到货后入库]

 J --> H

 H --> K[车间执行(MES)]

 K --> L[完工入库]

 L --> M[质检出库/发运]

 M --> N[账务结算/成本核算]

4.2 BOM 展开

BOM 展开就是从成品沿树向下,把每个组件按数量系数乘开,得到物料需求清单(MRP 的输入)。

flowchart LR

 A[主产品] --> B[零件A x2]

 A --> C[零件B x1]

 B --> D[原料A1 x3]

 C --> E[原料B1 x2]

说明:BOM 要支持替代件、备选供应商与采购批量规则(MOQ、批量折扣)。


5 开发技巧与实现建议

  1. 领域驱动设计(DDD):把业务模块按边界上下文划分(Sales Context、Production Context、Procurement Context、Inventory Context、Accounting Context、Engineering Context)。每个上下文内部聚合根、领域事件、实体和仓储接口清晰。
  2. 事件驱动 & 异步:订单确认、采购到货、完工入库等用事件驱动,MQ(RabbitMQ/Kafka)保证可靠投递与重试机制,事件要幂等。
  3. 事务处理:跨服务事务用补偿模式(Saga)。例如生产完工后需同时扣库并生成财务凭证,采用本地事务并发布事件,若其中一环失败执行补偿。
  4. 幂等与唯一约束:接口设计幂等键(order_id、request_id),避免重复下单或重复处理回调。
  5. BOM 版本管理:BOM 与 Routings 都要有版本、变更记录与生效日期,变更在生效点前的订单应继续使用旧版本。
  6. 排产策略:先实现简单优先级+物料可用排产,再演进到带资源约束的 APS。初期用启发式调度(FCFS + 优先级),后期可引入 ILP 或遗传算法优化。
  7. 性能:缓存热点数据(物料、BOM、客户信用)到 Redis,MRP 批量计算使用批处理 / 后台任务避免阻塞前端请求。
  8. 接口设计:REST + JSON 做边界 API;内部服务通信建议 gRPC(高效)或 HTTP + 认证。
  9. 数据建模:BOM/物料/工艺的数据模型要支持历史快照,以便追溯成本和质量问题。
  10. 测试:建立领域单元测试、集成测试、合同测试(Consumer-Driven Contract)来保证微服务兼容。

6 参考代码

下面给出一个 Node.js(TypeScript)示例:包含数据库 schema、关键 API(订单创建)、BOM 展开函数、简单 MRP/排产触发示例。示例基于 Express + TypeORM + RabbitMQ。代码为参考级别,真实产品需要补充权限、安全与完整错误处理。

// package.json (仅依赖展示)

// {

//   "name": "mto-erp-sample",

//   "dependencies": {

//     "express": "^4.18.2",

//     "typeorm": "^0.3.12",

//     "pg": "^8.10.0",

//     "amqplib": "^0.8.0",

//     "reflect-metadata": "^0.1.13"

//   }

// }

/* src/entity/Material.ts */

import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";

@Entity()

export class Material {

 @PrimaryGeneratedColumn()

 id: number;

 @Column({ unique: true })

 code: string;

 @Column()

 name: string;

 @Column({ default: 0 })

 leadTimeDays: number; // 采购交期

 @Column({ default: 0 })

 safetyStock: number;

}

/* src/entity/BOM.ts */

import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from "typeorm";

@Entity()

export class BOM {

 @PrimaryGeneratedColumn()

 id: number;

 @Column()

 productCode: string; // 成品/半成品代码

 @Column()

 componentCode: string;

 @Column("float")

 qty: number; // 每个成品需要的数量

 @Column({ nullable: true })

 effectiveFrom?: Date;

 @Column({ nullable: true })

 version?: string;

}

/* src/entity/SalesOrder.ts */

import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";

@Entity()

export class SalesOrder {

 @PrimaryGeneratedColumn()

 id: number;

 @Column({ unique: true })

 orderNo: string;

 @Column()

 productCode: string;

 @Column("int")

 qty: number;

 @Column()

 dueDate: Date;

 @Column({ default: 'CREATED' })

 status: string;

}

/* src/app.ts */

import express from "express";

import "reflect-metadata";

import { DataSource } from "typeorm";

import { Material } from "./entity/Material";

import { BOM } from "./entity/BOM";

import { SalesOrder } from "./entity/SalesOrder";

import amqp from "amqplib";

const app = express();

app.use(express.json());

const AppDataSource = new DataSource({

 type: "postgres",

 host: process.env.DB_HOST || "localhost",

 port: 5432,

 username: "postgres",

 password: "postgres",

 database: "mto_erp",

 entities: [Material, BOM, SalesOrder],

 synchronize: true,

});

let channel: amqp.Channel | null = null;

async function initMQ(){

 const conn = await amqp.connect(process.env.RABBIT_URL || "amqp://localhost");

 channel = await conn.createChannel();

 await channel.assertQueue("order.events", { durable: true });

}

AppDataSource.initialize().then(() => {

 console.log("DB connected");

 initMQ().then(()=>console.log("MQ connected"));

});

/* Helper: 展开 BOM(多级) */

async function explodeBOM(productCode: string, qty: number, ds: DataSource) {

 const bomRepo = ds.getRepository(BOM);

 const materialNeeds: Record<string, number> = {};

 // DFS 展开

 async function dfs(code: string, multiplier: number) {

   const nodes = await bomRepo.find({ where: { productCode: code } });

   if (!nodes || nodes.length === 0) {

     // code 是原料或外购件

     materialNeeds[code] = (materialNeeds[code] || 0) + multiplier;

     return;

   }

   for (const n of nodes) {

     await dfs(n.componentCode, multiplier * n.qty);

   }

 }

 await dfs(productCode, qty);

 return materialNeeds; // { materialCode: totalQty }

}

/* 简单 MRP:根据库存/安全库存判断是否需要采购(示例短版) */

async function simpleMRP(productCode: string, qty: number, ds: DataSource) {

 const needs = await explodeBOM(productCode, qty, ds);

 const materialRepo = ds.getRepository(Material);

 const results: Array<{ code: string; need: number; onHand: number; toPurchase: number }> = [];

 for (const code of Object.keys(needs)) {

   const m = await materialRepo.findOneBy({ code });

   const onHand = m ? 0 : 0; // 假设从库存服务获取,示例里用 0

   const safety = m ? m.safetyStock : 0;

   const need = needs[code];

   const toPurchase = Math.max(0, need + safety - onHand);

   results.push({ code, need, onHand, toPurchase });

 }

 return results;

}

/* 创建订单 API:保存订单 -> 触发简单 MRP -> 发布事件给采购/生产 */

app.post("/orders", async (req, res) => {

 const ds = AppDataSource;

 const repo = ds.getRepository(SalesOrder);

 const { orderNo, productCode, qty, dueDate } = req.body;

 try {

   const so = repo.create({ orderNo, productCode, qty, dueDate, status: 'CONFIRMED' });

   await repo.save(so);

   // 1) 计算物料需求

   const mrp = await simpleMRP(productCode, qty, ds);

   // 2) 发布事件

   const payload = { type: 'OrderConfirmed', data: { orderNo, productCode, qty, mrp } };

   if (channel) {

     channel.sendToQueue("order.events", Buffer.from(JSON.stringify(payload)), { persistent: true });

   }

   return res.json({ ok: true, order: so, mrp });

 } catch (err) {

   console.error(err);

   return res.status(500).json({ ok: false, message: 'error' });

 }

});

app.listen(3000, () => {

 console.log("Server started on 3000");

});

代码说明

  • explodeBOM:简单的递归展开 BOM,现实中应加缓存、防止循环引用、处理替代件与版本。
  • simpleMRP:示例只计算了“需要采购量”,实际需接库存服务(或 DB 的库存表)、考虑在途、已下达采购单与占用量。
  • 事件 order.events 可以被采购服务和生产服务消费,做下游动作(自动转采购单、生成生产工单或进入排产队列)。
  • 真实生产需考虑事务、重试与幂等(例如对 MQ 消费要实现去重逻辑)。

7 部署、运维与上线注意事项

  1. 滚动切换 + 灰度发布:对关键功能(MRP、排产)建议灰度推送,并在真实订单上做 shadow run(并行跑新系统但不影响生产)观察差异。
  2. 数据迁移:老 ERP 向新 ERP 的物料、BOM、库存、历史订单迁移需要数据映射、清洗与多轮比对。
  3. 监控与告警:关键指标(队列堆积、API 延迟、MRP 执行失败率、采购超期率)必须监控并设置自动告警。
  4. 安全性:API 网关开 TLS、RBAC 权限分层、审计日志、敏感资料加密(客户信息、成本数据)。
  5. 备份与灾备:数据库定期快照、跨可用区部署、消息中间件持久化配置。

8 实现效果与关键 KPI

实现后企业常见收益指标:

  • 订单交付及时率提升(目标 +10% ~ +30%)。
  • 关键物料缺料率下降(目标 -20% ~ -60%),因为 MRP 针对订单拉动更精准。
  • 在制品周转天数(WIP)下降,资金占用降低。
  • 订单到交付的透明度提升:客户满意度和重复订单率上升。 KPI 例如:按单成本偏差率、采购到货准时率、车间按时完工率、库存周转率。

9 FAQ

FAQ1:MTO 与 MTS 的 ERP 在设计上最大的不同是什么?

MTO(按单生产)与 MTS(按库存生产)最大的不同在“需求驱动的起点”和“库存应对方式”。MTS 更强调安全库存与预测驱动的补货,ERP 需侧重预测与补货策略;而 MTO 则是订单驱动,ERP 的核心是快速把单转换成可执行的生产计划并精确计算物料需求。具体到系统设计,MTO 系统要更强调 BOM 的配置能力、订单级成本核算、工程变更管理、以及灵活的排产策略(以响应订单交期)。此外,MTO 更依赖与供应链的即时协同——供应商交期、外协能力、在途可视化都更关键。

FAQ2:我们公司只有几十人规模,是否需要做微服务?

对于中小企业(几十人规模),直接从微服务开始并不总是最优选择。微服务带来的分布式复杂性(运维、监控、分布式事务、部署)会消耗大量资源。建议先走模块化单体或按边界上下文拆分的单体应用,重用团队开发/测试部署流程;当系统增长到一定规模或需要按模块独立扩展(例如生产服务需要高并发计算)时,再逐步把热点模块拆成微服务。无论选哪种路径,都要从一开始做好清晰的领域建模、API 设计和数据隔离,这样将来拆分会容易很多。

FAQ3:BOM 版本与工程变更如何管理?

BOM 和工艺路线应当支持版本控制与生效控制。实现上需把每个 BOM 记录为包含版本号与生效日期的实体;工程变更(ECO/ECN)应是一个工作流:申请 → 审核 → 排期生效。系统应支持“历史订单使用当时生效的 BOM/工艺”,也就是说在订单确认阶段就要把所用的 BOM 版本快照到订单/生产工单里,以便追溯。对于设计频繁变更的企业,推荐与 PLM 系统深度集成,并在 ERP 里保留 BOM 快照和变更日志,质检与财务也能依据不同版本进行成本与质量分析。

落地建议

  1. 先做业务建模、画清楚边界,不要急着编码。把订单生命周期、BOM 版本、物料主数据、在途/占用/可用定义清楚。
  2. 从模块化单体开始,优先落地销售、生产、库存与采购四个闭环,再引入财务对账。
  3. 采用事件驱动的异步架构,保证各模块解耦并易于扩展。
  4. 首版实现能跑、能对账、能追溯,后续再在排产优化、APS、供应商协同上迭代。
相关文章
|
3月前
|
供应链 JavaScript 数据挖掘
一套SaaS ERP管理系统源码,生产管理系统源代码
小微企业SaaS ERP系统,基于SpringBoot+Vue+UniAPP开发,集成进销存、采购销售、MRP生产、财务、CRM、OA等全流程管理功能,支持自定义表单与工作流,助力企业数字化转型。
281 1
|
4月前
|
供应链 JavaScript BI
如何2小时搭建一套(离散制造-MTO)ERP系统?
针对离散制造MTO模式痛点,本文分享如何用零代码工具两小时内搭建极简ERP系统,实现订单、生产、物料与库存实时联动,提升交付准时率与管理透明度,降低出错与成本。
|
4月前
|
供应链 监控 JavaScript
如何开发ERP(离散制造-MTO)系统中的库存管理板块(附架构图+流程图+代码参考)
本文详解MTO模式下ERP库存管理的关键作用,涵盖核心模块、业务流程、开发技巧与代码示例,助力制造企业提升库存周转率、降低缺货风险,实现高效精准的库存管控。
|
4月前
|
自然语言处理 安全 搜索推荐
ERP系统上手指南:首页导航+常见操作详解!
本文是ERP系统入门教程首篇,针对新手解决“如何上手”问题。涵盖登录、界面导航、基础操作、权限管理及常见问题,以简道云为例,手把手教你从0开始使用ERP,打通企业数字化第一关。
|
3月前
|
Cloud Native Serverless API
微服务架构实战指南:从单体应用到云原生的蜕变之路
🌟蒋星熠Jaxonic,代码为舟的星际旅人。深耕微服务架构,擅以DDD拆分服务、构建高可用通信与治理体系。分享从单体到云原生的实战经验,探索技术演进的无限可能。
微服务架构实战指南:从单体应用到云原生的蜕变之路
|
弹性计算 API 持续交付
后端服务架构的微服务化转型
本文旨在探讨后端服务从单体架构向微服务架构转型的过程,分析微服务架构的优势和面临的挑战。文章首先介绍单体架构的局限性,然后详细阐述微服务架构的核心概念及其在现代软件开发中的应用。通过对比两种架构,指出微服务化转型的必要性和实施策略。最后,讨论了微服务架构实施过程中可能遇到的问题及解决方案。
|
Cloud Native Devops 云计算
云计算的未来:云原生架构与微服务的革命####
【10月更文挑战第21天】 随着企业数字化转型的加速,云原生技术正迅速成为IT行业的新宠。本文深入探讨了云原生架构的核心理念、关键技术如容器化和微服务的优势,以及如何通过这些技术实现高效、灵活且可扩展的现代应用开发。我们将揭示云原生如何重塑软件开发流程,提升业务敏捷性,并探索其对企业IT架构的深远影响。 ####
386 3
|
6月前
|
缓存 Cloud Native Java
Java 面试微服务架构与云原生技术实操内容及核心考点梳理 Java 面试
本内容涵盖Java面试核心技术实操,包括微服务架构(Spring Cloud Alibaba)、响应式编程(WebFlux)、容器化(Docker+K8s)、函数式编程、多级缓存、分库分表、链路追踪(Skywalking)等大厂高频考点,助你系统提升面试能力。
367 0
|
Java 开发者 微服务
从单体到微服务:如何借助 Spring Cloud 实现架构转型
**Spring Cloud** 是一套基于 Spring 框架的**微服务架构解决方案**,它提供了一系列的工具和组件,帮助开发者快速构建分布式系统,尤其是微服务架构。
1358 69
从单体到微服务:如何借助 Spring Cloud 实现架构转型

热门文章

最新文章