在离散制造-MTO(Make-To-Order,按订单生产)的场景下,客户就是制造的起点。客户信息、跟进记录和客户分析直接决定报价准度、交期管理、产能排产和资金回笼效率。很多企业把ERP的“客户管理”当成CRM的简单复制,但在MTO场景里它需要更紧密地和BOM、工艺路线、报价模块、订单、交付与售后衔接。本文将给出一套可实施的客户管理模块设计(包含架构图、流程图、功能拆解、开发技巧、以及一个较大的参考代码),帮助企业快速搭建或改造适配离散制造-MTO的客户管理板块。
本文你将了解
注:本文示例所用方案模板:简道云ERP系统,给大家示例的是一些通用的功能和模块,都是支持自定义修改的,你可以根据自己的需求修改里面的功能。
什么是 ERP(离散制造-MTO)系统? 简要说:ERP 是企业资源计划系统。离散制造指产品是离散的(零部件、装配件),MTO 表示多数生产是按订单生产而非库存生产。MTO 最大的挑战是订单多变、每单可能不同(BOM、交期、工序不同),因此前端的客户信息和跟进记录直接影响制造端决策。
为什么要在 ERP 里做客户管理而不是单独用 CRM? 因为在 MTO 场景下:客户的需求常常牵涉到工艺、BOM、报价与交期。把客户管理放在 ERP,能实现客户信息与报价、销售订单、生产排程、采购需求的无缝联动,减少信息孤岛与重复录入,提升响应速度与准交率。
核心要解决的问题:
关键功能围绕三大对象:客户(Customer)、跟进记录(FollowUp)、客户分析(Analysis)。
下面给出一个典型的模块化架构(微服务或单体模块化均可适配):
graph TD
A[前端应用:销售/客服/售后] -->|REST/GraphQL| B[API 网关 / 后端服务]
B --> C[客户管理服务]
C --> D[(数据库:Customer, FollowUp, Tags, Events)]
C --> E[分析服务 / OLAP层]
B --> F[订单服务]
B --> G[报价服务]
B --> H[生产排程服务]
E --> I[BI / 报表 & 告警]
C --> J[消息队列(通知/提醒/钉钉/邮件)]
subgraph ThirdParty
K[外部CRM/线索系统] -->|同步 / 导入| B
L[电话/邮件系统] -->|Webhook| C
end
说明:客户管理处在 ERP 的核心位置,需要与订单、报价、生产排程和外部通信系统互通,另外提供向分析服务输出维度化数据以支持 BI 报表和预警。
总体客户生命周期流程:线索 → 客户建立 → 跟进(多轮)→ 报价/试产 → 下单 → 交付 → 售后/回访 → 留存或流失。
下面是流程图(Mermaid):
flowchart TD
Lead[线索/客户线索] -->|验证| CustCreate[建立客户档案]
CustCreate --> Follow[跟进记录(多次)]
Follow -->|需求确认| Quote[报价/评审]
Quote -->|通过| SO[销售订单]
SO --> Prod[生产排程]
Prod --> Delivery[交付]
Delivery --> AfterSale[售后/回访]
AfterSale -->|满意| Retain[留存]
AfterSale -->|不满意| Churn[流失/降级]
必有字段(最小集):
设计要点:
跟进记录要能精确复盘,最少字段:
实现要点:
关键指标:
实现建议:
下面给出一个便于落地的后端示例,包含实体定义、主要 API、以及一个示例分析 SQL(用于计算 RFM)。代码经过注释,作为开发参考。
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, OneToMany, Index } from 'typeorm';
import { FollowUp } from './FollowUp';
@Entity({ name: 'customers' })
export class Customer {
@PrimaryGeneratedColumn('uuid')
id: string;
@Index()
@Column({ type: 'varchar', length: 200 })
name: string;
@Column({ type: 'varchar', length: 100, nullable: true })
short_name: string;
@Column({ type: 'varchar', length: 50, nullable: true })
type: string; // 'direct' | 'distributor' etc.
@Column({ type: 'varchar', length: 100, nullable: true })
industry: string;
@Column({ type: 'varchar', length: 100, nullable: true })
region: string;
@Column({ type: 'jsonb', nullable: true })
contacts: { name: string; phone?: string; email?: string; title?: string }[];
@Column({ type: 'decimal', precision: 18, scale: 2, default: 0 })
total_amount: number; // 累计下单金额冗余
@Column({ type: 'timestamp', nullable: true })
last_ordered_at: Date;
@Column({ type: 'varchar', length: 50, nullable: true })
tags: string; // simple csv tags, or use relation table
@Column({ type: 'boolean', default: true })
is_active: boolean;
@CreateDateColumn()
created_at: Date;
@UpdateDateColumn()
updated_at: Date;
@OneToMany(() => FollowUp, fu => fu.customer)
followUps: FollowUp[];
}
// src/entities/FollowUp.ts
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, CreateDateColumn, Index } from 'typeorm';
import { Customer } from './Customer';
@Entity({ name: 'follow_ups' })
export class FollowUp {
@PrimaryGeneratedColumn('uuid')
id: string;
@Index()
@Column()
customerId: string;
@ManyToOne(() => Customer, c => c.followUps)
customer: Customer;
@Column()
creatorId: string; // user id
@Column({ type: 'varchar', length: 50 })
// src/entities/FollowUp.ts
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, CreateDateColumn, Index } from 'typeorm';
import { Customer } from './Customer';
@Entity({ name: 'follow_ups' })
export class FollowUp {
@PrimaryGeneratedColumn('uuid')
id: string;
@Index()
@Column()
customerId: string;
@ManyToOne(() => Customer, c => c.followUps)
customer: Customer;
@Column()
creatorId: string; // user id
@Column({ type: 'varchar', length: 50 })
type: string; // phone/email/visitation/meeting
@Column({ type: 'text' })
content: string;
@Column({ type: 'varchar', length: 50, nullable: true })
result: string; // 意向、报价中、失效等
@Column({ type: 'timestamp', nullable: true })
next_follow_at: Date;
@Column({ type: 'jsonb', nullable: true })
attachments: { name: string; url: string }[];
@CreateDateColumn()
created_at: Date;
}
交付时建议验收列表(最少项):
上线建议:
不一定。很多企业会同时使用专业 CRM(例如 Salesforce)和 ERP。在 MTO 场景下,关键是“数据一致性”和“流程联动”。建议做法是评估两个系统中的“主数据”归属:如果销售线索、市场活动、外部营销自动化以 CRM 为主,把 CRM 当作前端线索系统;而把 ERP 作为订单、报价、生产与账务的主系统。通过同步(双向或单向)接口,每次将客户主档和重要字段(信用等级、结算方式、最近下单时间)同步到 ERP,并确保在 ERP 中有来源标记与冲突解决策略。若预算允许,也可以把 CRM 的可视化和营销能力通过插件或嵌入方式接入 ERP 界面,减少用户切换。总之,是否合并要基于企业的组织方式、数据规模与成本评估,而不是简单地“全部搬到 ERP”。
客户重复通常来自多个入口(手工录入、导入、业务员个人 excel、外部 CRM 同步)。技术上要做三项工作:1)在写入层进行幂等和去重:用税号、统一社会信用码、公司名称 + 联系人电话等做多字段匹配,优先使用精确字段(税号)做唯一性约束;2)建立清洗与合并流程:提供后台合并工具,人工审核并合并重复档案(保留历史跟进与订单);3)在 UI 层提供实时提示:输入公司名时做模糊检索提示可能重复的客户,提示业务员先核查再新增。组织上要制定规范:谁有权限创建客户、创建时必须填写哪几个关键字段(税号/联系人/负责人),并做定期数据质量检查和指标(重复率、空值率)考核。
跟进记录是业务的核心“记忆体”。要把它用好,可以做三件事:1)把跟进记录结构化,关键字段(跟进类型、结果、下次跟进时间、意向强度)标准化,便于机器识别;2)基于结构化字段建立规则引擎,比如“跟进结果=报价中 && 下次跟进时间 <= 今天 且 意向强度 >= 高”触发提醒给对应的销售并在系统中标红;3)把这些规则与分析结合,形成闭环优化:统计哪些跟进组合(如 1 次电话 + 1 次上门)转化率高,把最优跟进路径作为团队最佳实践。技术上提醒可以通过消息队列+通知服务(邮件、站内、企业微信/钉钉)实现;效果评估需要埋点和 A/B 测试(例如对一组客户采用系统化提醒,另一组不采用,观察成单率差异)。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。