Skip to main content

ERP 企业资源规划系统设计

一、系统概述

1.1 系统简介

ERP(Enterprise Resource Planning)企业资源规划系统是一个集成化的企业管理系统,整合企业的财务、采购、生产、销售、库存、人力资源等核心业务流程,实现企业资源的优化配置和高效利用。

1.2 核心价值

价值点说明预期效果
🎯 流程整合打通企业全业务流程流程效率提升 50%
📊 数据统一建立统一数据中心数据准确率 99.5%
🔄 资源优化优化资源配置资源利用率提升 40%
📈 决策支持实时数据分析决策效率提升 45%
🚀 成本控制精细化成本管理成本降低 30%

1.3 业务需求

核心功能模块

  • 财务管理:总账、应收应付、成本核算、资产管理
  • 采购管理:采购申请、采购订单、供应商管理、到货验收
  • 销售管理:销售订单、销售出库、客户管理、销售分析
  • 库存管理:库存管理、出入库管理、库存盘点、库存预警
  • 生产管理:生产计划、生产订单、物料需求、生产统计
  • 人力资源:员工管理、考勤管理、薪资管理、绩效管理
  • 基础数据:组织架构、权限管理、参数配置

非功能需求

  • 高可用性:系统可用性 99.9%
  • 数据一致性:确保各模块数据一致性
  • 权限安全:严格的权限控制体系
  • 性能要求:支持 2000+ 并发用户
  • 扩展性:支持多组织、多工厂、多币种

二、系统架构

2.1 技术架构

2.2 采购到付款流程

微服务划分

1. 基础服务 (erp-base-service)

java
1- 组织管理 (Organization)
2- 部门管理 (Department)
3- 用户管理 (User)
4- 角色权限 (Role & Permission)
5- 数据字典 (Dictionary)
6- 系统参数 (System Config)

2. 财务服务 (erp-finance-service)

java
1- 总账管理 (General Ledger)
2- 应收账款 (Accounts Receivable)
3- 应付账款 (Accounts Payable)
4- 成本核算 (Cost Accounting)
5- 资产管理 (Asset Management)
6- 报表管理 (Financial Report)

3. 采购服务 (erp-purchase-service)

java
1- 采购申请 (Purchase Request)
2- 采购订单 (Purchase Order)
3- 供应商管理 (Supplier)
4- 到货验收 (Goods Receipt)
5- 采购退货 (Purchase Return)

4. 销售服务 (erp-sales-service)

java
1- 销售订单 (Sales Order)
2- 销售出库 (Sales Delivery)
3- 销售退货 (Sales Return)
4- 客户管理 (Customer)
5- 价格管理 (Pricing)
6- 信用管理 (Credit Management)

5. 库存服务 (erp-inventory-service)

java
1- 库存管理 (Inventory)
2- 出入库管理 (Inbound/Outbound)
3- 库存调拨 (Transfer)
4- 库存盘点 (Stock Taking)
5- 批次管理 (Batch Management)

6. 生产服务 (erp-production-service)

java
1- 生产计划 (Production Plan)
2- 生产订单 (Production Order)
3- 物料清单 (BOM)
4- 工艺路线 (Routing)
5- 生产领料 (Material Issue)
6- 生产入库 (Production Receipt)

7. 人力资源服务 (erp-hr-service)

java
1- 员工管理 (Employee)
2- 考勤管理 (Attendance)
3- 薪资管理 (Payroll)
4- 绩效管理 (Performance)
5- 招聘管理 (Recruitment)

数据模型设计

核心表结构

1. 组织表 (organization)

sql
1CREATE TABLE organization (
2 id BIGINT PRIMARY KEY AUTO_INCREMENT,
3 org_code VARCHAR(50) NOT NULL UNIQUE COMMENT '组织编码',
4 org_name VARCHAR(200) NOT NULL COMMENT '组织名称',
5 parent_id BIGINT COMMENT '父组织ID',
6 org_type TINYINT NOT NULL COMMENT '组织类型:1-集团,2-公司,3-工厂,4-部门',
7 level INT NOT NULL COMMENT '层级',
8 sort_order INT DEFAULT 0 COMMENT '排序',
9 contact_person VARCHAR(50) COMMENT '联系人',
10 contact_phone VARCHAR(20) COMMENT '联系电话',
11 address VARCHAR(200) COMMENT '地址',
12 status TINYINT DEFAULT 1 COMMENT '状态:1-启用,0-禁用',
13 create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
14 update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
15 INDEX idx_parent (parent_id),
16 INDEX idx_code (org_code)
17) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='组织表';

2. 采购订单表 (purchase_order)

sql
1CREATE TABLE purchase_order (
2 id BIGINT PRIMARY KEY AUTO_INCREMENT,
3 order_no VARCHAR(50) NOT NULL UNIQUE COMMENT '采购单号',
4 org_id BIGINT NOT NULL COMMENT '组织ID',
5 supplier_id BIGINT NOT NULL COMMENT '供应商ID',
6 order_date DATE NOT NULL COMMENT '订单日期',
7 expected_date DATE COMMENT '期望到货日期',
8 order_type TINYINT DEFAULT 1 COMMENT '订单类型:1-标准采购,2-紧急采购,3-委外加工',
9 total_amount DECIMAL(15,2) NOT NULL DEFAULT 0 COMMENT '订单总额',
10 tax_amount DECIMAL(15,2) DEFAULT 0 COMMENT '税额',
11 discount_amount DECIMAL(15,2) DEFAULT 0 COMMENT '折扣金额',
12 final_amount DECIMAL(15,2) NOT NULL COMMENT '最终金额',
13 currency_code VARCHAR(10) DEFAULT 'CNY' COMMENT '币种',
14 payment_term VARCHAR(100) COMMENT '付款条件',
15 delivery_address VARCHAR(200) COMMENT '收货地址',
16 status TINYINT DEFAULT 1 COMMENT '状态:1-草稿,2-待审批,3-审批中,4-已审批,5-执行中,6-已完成,7-已取消',
17 buyer_id BIGINT COMMENT '采购员ID',
18 approver_id BIGINT COMMENT '审批人ID',
19 approve_time DATETIME COMMENT '审批时间',
20 remark VARCHAR(500) COMMENT '备注',
21 create_user_id BIGINT COMMENT '创建人ID',
22 create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
23 update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
24 INDEX idx_order_no (order_no),
25 INDEX idx_supplier (supplier_id),
26 INDEX idx_status (status),
27 INDEX idx_order_date (order_date)
28) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='采购订单表';

3. 采购订单明细表 (purchase_order_detail)

sql
1CREATE TABLE purchase_order_detail (
2 id BIGINT PRIMARY KEY AUTO_INCREMENT,
3 order_id BIGINT NOT NULL COMMENT '采购单ID',
4 line_no INT NOT NULL COMMENT '行号',
5 product_id BIGINT NOT NULL COMMENT '物料ID',
6 product_code VARCHAR(50) NOT NULL COMMENT '物料编码',
7 product_name VARCHAR(200) NOT NULL COMMENT '物料名称',
8 spec VARCHAR(200) COMMENT '规格',
9 unit VARCHAR(20) COMMENT '单位',
10 quantity DECIMAL(10,2) NOT NULL COMMENT '数量',
11 unit_price DECIMAL(10,4) NOT NULL COMMENT '单价',
12 tax_rate DECIMAL(5,2) DEFAULT 0 COMMENT '税率(%)',
13 amount DECIMAL(15,2) NOT NULL COMMENT '金额',
14 received_quantity DECIMAL(10,2) DEFAULT 0 COMMENT '已收货数量',
15 invoiced_quantity DECIMAL(10,2) DEFAULT 0 COMMENT '已开票数量',
16 expected_date DATE COMMENT '期望到货日期',
17 warehouse_id BIGINT COMMENT '收货仓库ID',
18 location_id BIGINT COMMENT '收货库位ID',
19 remark VARCHAR(500) COMMENT '备注',
20 create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
21 update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
22 INDEX idx_order (order_id),
23 INDEX idx_product (product_id)
24) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='采购订单明细表';

4. 销售订单表 (sales_order)

sql
1CREATE TABLE sales_order (
2 id BIGINT PRIMARY KEY AUTO_INCREMENT,
3 order_no VARCHAR(50) NOT NULL UNIQUE COMMENT '销售单号',
4 org_id BIGINT NOT NULL COMMENT '组织ID',
5 customer_id BIGINT NOT NULL COMMENT '客户ID',
6 order_date DATE NOT NULL COMMENT '订单日期',
7 delivery_date DATE COMMENT '要求交货日期',
8 order_type TINYINT DEFAULT 1 COMMENT '订单类型:1-标准销售,2-预售,3-样品',
9 total_amount DECIMAL(15,2) NOT NULL DEFAULT 0 COMMENT '订单总额',
10 tax_amount DECIMAL(15,2) DEFAULT 0 COMMENT '税额',
11 discount_amount DECIMAL(15,2) DEFAULT 0 COMMENT '折扣金额',
12 final_amount DECIMAL(15,2) NOT NULL COMMENT '最终金额',
13 currency_code VARCHAR(10) DEFAULT 'CNY' COMMENT '币种',
14 payment_term VARCHAR(100) COMMENT '付款条件',
15 delivery_address VARCHAR(200) COMMENT '交货地址',
16 contact_person VARCHAR(50) COMMENT '联系人',
17 contact_phone VARCHAR(20) COMMENT '联系电话',
18 status TINYINT DEFAULT 1 COMMENT '状态:1-草稿,2-待审批,3-审批中,4-已审批,5-执行中,6-已完成,7-已取消',
19 sales_person_id BIGINT COMMENT '销售员ID',
20 approver_id BIGINT COMMENT '审批人ID',
21 approve_time DATETIME COMMENT '审批时间',
22 remark VARCHAR(500) COMMENT '备注',
23 create_user_id BIGINT COMMENT '创建人ID',
24 create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
25 update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
26 INDEX idx_order_no (order_no),
27 INDEX idx_customer (customer_id),
28 INDEX idx_status (status),
29 INDEX idx_order_date (order_date)
30) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='销售订单表';

5. 生产订单表 (production_order)

sql
1CREATE TABLE production_order (
2 id BIGINT PRIMARY KEY AUTO_INCREMENT,
3 order_no VARCHAR(50) NOT NULL UNIQUE COMMENT '生产单号',
4 org_id BIGINT NOT NULL COMMENT '组织ID',
5 workshop_id BIGINT COMMENT '车间ID',
6 product_id BIGINT NOT NULL COMMENT '产品ID',
7 product_code VARCHAR(50) NOT NULL COMMENT '产品编码',
8 product_name VARCHAR(200) NOT NULL COMMENT '产品名称',
9 spec VARCHAR(200) COMMENT '规格',
10 unit VARCHAR(20) COMMENT '单位',
11 plan_quantity DECIMAL(10,2) NOT NULL COMMENT '计划数量',
12 actual_quantity DECIMAL(10,2) DEFAULT 0 COMMENT '实际完工数量',
13 qualified_quantity DECIMAL(10,2) DEFAULT 0 COMMENT '合格数量',
14 defective_quantity DECIMAL(10,2) DEFAULT 0 COMMENT '不合格数量',
15 bom_id BIGINT COMMENT 'BOM ID',
16 routing_id BIGINT COMMENT '工艺路线ID',
17 plan_start_date DATE NOT NULL COMMENT '计划开始日期',
18 plan_end_date DATE NOT NULL COMMENT '计划完成日期',
19 actual_start_date DATE COMMENT '实际开始日期',
20 actual_end_date DATE COMMENT '实际完成日期',
21 source_type TINYINT COMMENT '来源类型:1-销售订单,2-库存补货,3-其他',
22 source_no VARCHAR(50) COMMENT '来源单号',
23 priority TINYINT DEFAULT 0 COMMENT '优先级:0-普通,1-重要,2-紧急',
24 status TINYINT DEFAULT 1 COMMENT '状态:1-计划,2-已下达,3-生产中,4-已完工,5-已入库,6-已取消',
25 manager_id BIGINT COMMENT '生产负责人ID',
26 remark VARCHAR(500) COMMENT '备注',
27 create_user_id BIGINT COMMENT '创建人ID',
28 create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
29 update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
30 INDEX idx_order_no (order_no),
31 INDEX idx_product (product_id),
32 INDEX idx_status (status),
33 INDEX idx_plan_date (plan_start_date, plan_end_date)
34) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='生产订单表';

6. 物料清单表 (bom)

sql
1CREATE TABLE bom (
2 id BIGINT PRIMARY KEY AUTO_INCREMENT,
3 bom_no VARCHAR(50) NOT NULL UNIQUE COMMENT 'BOM编号',
4 product_id BIGINT NOT NULL COMMENT '产品ID',
5 product_code VARCHAR(50) NOT NULL COMMENT '产品编码',
6 product_name VARCHAR(200) NOT NULL COMMENT '产品名称',
7 version VARCHAR(20) NOT NULL COMMENT '版本',
8 bom_type TINYINT DEFAULT 1 COMMENT 'BOM类型:1-标准BOM,2-配置BOM,3-销售BOM',
9 is_current TINYINT DEFAULT 0 COMMENT '是否当前版本:0-否,1-是',
10 effective_date DATE COMMENT '生效日期',
11 expire_date DATE COMMENT '失效日期',
12 status TINYINT DEFAULT 1 COMMENT '状态:1-草稿,2-已审批,3-已失效',
13 remark VARCHAR(500) COMMENT '备注',
14 create_user_id BIGINT COMMENT '创建人ID',
15 create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
16 update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
17 UNIQUE KEY uk_product_version (product_id, version),
18 INDEX idx_bom_no (bom_no),
19 INDEX idx_product (product_id)
20) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='物料清单表';

7. 物料清单明细表 (bom_detail)

sql
1CREATE TABLE bom_detail (
2 id BIGINT PRIMARY KEY AUTO_INCREMENT,
3 bom_id BIGINT NOT NULL COMMENT 'BOM ID',
4 line_no INT NOT NULL COMMENT '行号',
5 material_id BIGINT NOT NULL COMMENT '物料ID',
6 material_code VARCHAR(50) NOT NULL COMMENT '物料编码',
7 material_name VARCHAR(200) NOT NULL COMMENT '物料名称',
8 spec VARCHAR(200) COMMENT '规格',
9 unit VARCHAR(20) COMMENT '单位',
10 quantity DECIMAL(10,4) NOT NULL COMMENT '用量',
11 loss_rate DECIMAL(5,2) DEFAULT 0 COMMENT '损耗率(%)',
12 is_key_material TINYINT DEFAULT 0 COMMENT '是否关键物料:0-否,1-是',
13 substitute_group VARCHAR(20) COMMENT '替代组',
14 remark VARCHAR(500) COMMENT '备注',
15 create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
16 INDEX idx_bom (bom_id),
17 INDEX idx_material (material_id)
18) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='物料清单明细表';

8. 会计科目表 (account)

sql
1CREATE TABLE account (
2 id BIGINT PRIMARY KEY AUTO_INCREMENT,
3 account_code VARCHAR(50) NOT NULL UNIQUE COMMENT '科目编码',
4 account_name VARCHAR(200) NOT NULL COMMENT '科目名称',
5 parent_id BIGINT COMMENT '父科目ID',
6 level INT NOT NULL COMMENT '层级',
7 account_type TINYINT NOT NULL COMMENT '科目类型:1-资产,2-负债,3-权益,4-成本,5-损益',
8 balance_direction TINYINT NOT NULL COMMENT '余额方向:1-借方,2-贷方',
9 is_leaf TINYINT DEFAULT 0 COMMENT '是否末级:0-否,1-是',
10 is_cash TINYINT DEFAULT 0 COMMENT '是否现金科目:0-否,1-是',
11 is_bank TINYINT DEFAULT 0 COMMENT '是否银行科目:0-否,1-是',
12 status TINYINT DEFAULT 1 COMMENT '状态:1-启用,0-禁用',
13 create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
14 update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
15 INDEX idx_code (account_code),
16 INDEX idx_parent (parent_id)
17) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会计科目表';

9. 凭证表 (voucher)

sql
1CREATE TABLE voucher (
2 id BIGINT PRIMARY KEY AUTO_INCREMENT,
3 voucher_no VARCHAR(50) NOT NULL UNIQUE COMMENT '凭证号',
4 org_id BIGINT NOT NULL COMMENT '组织ID',
5 voucher_date DATE NOT NULL COMMENT '凭证日期',
6 period VARCHAR(7) NOT NULL COMMENT '会计期间(YYYY-MM)',
7 voucher_type TINYINT DEFAULT 1 COMMENT '凭证类型:1-记账凭证,2-收款凭证,3-付款凭证,4-转账凭证',
8 total_debit DECIMAL(15,2) NOT NULL COMMENT '借方合计',
9 total_credit DECIMAL(15,2) NOT NULL COMMENT '贷方合计',
10 attachment_count INT DEFAULT 0 COMMENT '附件数量',
11 status TINYINT DEFAULT 1 COMMENT '状态:1-草稿,2-已审核,3-已记账',
12 maker_id BIGINT COMMENT '制单人ID',
13 checker_id BIGINT COMMENT '审核人ID',
14 check_time DATETIME COMMENT '审核时间',
15 poster_id BIGINT COMMENT '记账人ID',
16 post_time DATETIME COMMENT '记账时间',
17 remark VARCHAR(500) COMMENT '备注',
18 create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
19 update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
20 INDEX idx_voucher_no (voucher_no),
21 INDEX idx_org_period (org_id, period),
22 INDEX idx_date (voucher_date)
23) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='凭证表';

10. 凭证明细表 (voucher_detail)

sql
1CREATE TABLE voucher_detail (
2 id BIGINT PRIMARY KEY AUTO_INCREMENT,
3 voucher_id BIGINT NOT NULL COMMENT '凭证ID',
4 line_no INT NOT NULL COMMENT '行号',
5 account_id BIGINT NOT NULL COMMENT '科目ID',
6 account_code VARCHAR(50) NOT NULL COMMENT '科目编码',
7 account_name VARCHAR(200) NOT NULL COMMENT '科目名称',
8 summary VARCHAR(500) COMMENT '摘要',
9 debit_amount DECIMAL(15,2) DEFAULT 0 COMMENT '借方金额',
10 credit_amount DECIMAL(15,2) DEFAULT 0 COMMENT '贷方金额',
11 currency_code VARCHAR(10) DEFAULT 'CNY' COMMENT '币种',
12 exchange_rate DECIMAL(10,4) DEFAULT 1 COMMENT '汇率',
13 auxiliary_type VARCHAR(20) COMMENT '辅助核算类型',
14 auxiliary_id BIGINT COMMENT '辅助核算ID',
15 create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
16 INDEX idx_voucher (voucher_id),
17 INDEX idx_account (account_id)
18) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='凭证明细表';

核心业务流程

1. 采购到付款流程 (P2P)

1采购申请 → 采购订单 → 到货验收 → 采购入库 → 采购发票 → 付款
2 ↓ ↓ ↓ ↓ ↓ ↓
3 (待审批) (待执行) (待验收) (待入库) (待付款) (已完成)

关键步骤

  1. 创建采购申请(需求部门发起)
  2. 采购申请审批
  3. 创建采购订单(采购部门)
  4. 采购订单审批
  5. 到货验收(质检部门)
  6. 采购入库(仓库)
  7. 采购发票录入(财务)
  8. 应付款生成
  9. 付款处理
  10. 生成会计凭证

2. 订单到收款流程 (O2C)

1销售订单 → 销售发货 → 销售出库 → 销售发票 → 收款
2 ↓ ↓ ↓ ↓ ↓
3 (待审批) (待发货) (待出库) (待收款) (已完成)

关键步骤

  1. 创建销售订单
  2. 销售订单审批
  3. 信用检查
  4. 库存预留
  5. 销售发货
  6. 销售出库
  7. 销售发票开具
  8. 应收款生成
  9. 收款处理
  10. 生成会计凭证

3. 生产制造流程

1生产计划 → 物料需求 → 生产订单 → 生产领料 → 生产报工 → 完工入库
2 ↓ ↓ ↓ ↓ ↓ ↓
3 (计划) (需求分析) (已下达) (生产中) (已报工) (已完工)

关键步骤

  1. 制定生产计划(根据销售订单或库存补货)
  2. MRP 运算(物料需求计划)
  3. 生成生产订单
  4. 生产订单下达
  5. 生产领料(从仓库领取物料)
  6. 生产报工(记录生产进度)
  7. 质检(成品检验)
  8. 完工入库
  9. 成本核算

4. 月末结账流程

1期间检查 → 成本核算 → 损益结转 → 凭证审核 → 记账 → 结账

关键步骤

  1. 检查期间数据完整性
  2. 成本核算(材料成本、人工成本、制造费用)
  3. 自动生成结转凭证(损益结转、成本结转)
  4. 凭证审核
  5. 凭证记账
  6. 月末结账
  7. 生成财务报表

技术实现方案

1. 工作流引擎(审批流程)

使用 Flowable 实现审批流程:

java
1@Service
2public class PurchaseOrderWorkflowService {
3
4 @Autowired
5 private RuntimeService runtimeService;
6
7 @Autowired
8 private TaskService taskService;
9
10 /**
11 * 提交采购订单审批
12 */
13 public void submitForApproval(Long orderId) {
14 PurchaseOrder order = purchaseOrderMapper.selectById(orderId);
15
16 // 启动流程实例
17 Map<String, Object> variables = new HashMap<>();
18 variables.put("orderId", orderId);
19 variables.put("orderAmount", order.getFinalAmount());
20 variables.put("buyerId", order.getBuyerId());
21 variables.put("orgId", order.getOrgId());
22
23 ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(
24 "purchase_order_approval",
25 order.getOrderNo(),
26 variables
27 );
28
29 // 更新订单状态
30 order.setStatus(OrderStatus.PENDING_APPROVAL);
31 order.setProcessInstanceId(processInstance.getId());
32 purchaseOrderMapper.updateById(order);
33 }
34
35 /**
36 * 审批采购订单
37 */
38 public void approveOrder(String taskId, Long userId, boolean approved, String comment) {
39 // 完成任务
40 Map<String, Object> variables = new HashMap<>();
41 variables.put("approved", approved);
42 variables.put("approverId", userId);
43 variables.put("comment", comment);
44
45 taskService.complete(taskId, variables);
46
47 // 如果审批通过,更新订单状态
48 Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
49 String orderId = (String) runtimeService.getVariable(
50 task.getProcessInstanceId(),
51 "orderId"
52 );
53
54 PurchaseOrder order = purchaseOrderMapper.selectById(Long.parseLong(orderId));
55 if (approved) {
56 order.setStatus(OrderStatus.APPROVED);
57 } else {
58 order.setStatus(OrderStatus.REJECTED);
59 }
60 purchaseOrderMapper.updateById(order);
61 }
62}

2. 分布式事务(Seata)

使用 Seata 处理分布式事务:

java
1@Service
2public class SalesOrderService {
3
4 @Autowired
5 private SalesOrderMapper salesOrderMapper;
6
7 @Autowired
8 private InventoryServiceClient inventoryServiceClient;
9
10 @Autowired
11 private FinanceServiceClient financeServiceClient;
12
13 /**
14 * 创建销售订单(分布式事务)
15 */
16 @GlobalTransactional(name = "create-sales-order", rollbackFor = Exception.class)
17 public Long createSalesOrder(SalesOrderDTO dto) {
18 // 1. 创建销售订单
19 SalesOrder order = new SalesOrder();
20 BeanUtils.copyProperties(dto, order);
21 order.setOrderNo(generateOrderNo());
22 order.setStatus(OrderStatus.DRAFT);
23 salesOrderMapper.insert(order);
24
25 // 2. 创建订单明细
26 for (SalesOrderDetailDTO detailDto : dto.getDetails()) {
27 SalesOrderDetail detail = new SalesOrderDetail();
28 BeanUtils.copyProperties(detailDto, detail);
29 detail.setOrderId(order.getId());
30 salesOrderDetailMapper.insert(detail);
31
32 // 3. 预留库存(调用库存服务)
33 inventoryServiceClient.reserveInventory(
34 detailDto.getProductId(),
35 detailDto.getQuantity(),
36 order.getOrderNo()
37 );
38 }
39
40 // 4. 生成应收款(调用财务服务)
41 financeServiceClient.createReceivable(
42 order.getId(),
43 order.getCustomerId(),
44 order.getFinalAmount()
45 );
46
47 return order.getId();
48 }
49}

3. MRP 物料需求计划

java
1@Service
2public class MrpService {
3
4 @Autowired
5 private ProductionOrderMapper productionOrderMapper;
6
7 @Autowired
8 private BomService bomService;
9
10 @Autowired
11 private InventoryService inventoryService;
12
13 /**
14 * MRP 运算
15 */
16 public List<MaterialRequirement> calculateMrp(LocalDate startDate, LocalDate endDate) {
17 // 1. 获取生产计划
18 List<ProductionOrder> orders = productionOrderMapper.selectByDateRange(
19 startDate,
20 endDate
21 );
22
23 List<MaterialRequirement> requirements = new ArrayList<>();
24
25 for (ProductionOrder order : orders) {
26 // 2. 获取 BOM
27 List<BomDetail> bomDetails = bomService.getBomDetails(order.getBomId());
28
29 for (BomDetail detail : bomDetails) {
30 // 3. 计算物料需求
31 BigDecimal requireQty = detail.getQuantity()
32 .multiply(order.getPlanQuantity())
33 .multiply(BigDecimal.ONE.add(detail.getLossRate().divide(new BigDecimal("100"))));
34
35 // 4. 查询库存
36 BigDecimal availableQty = inventoryService.getAvailableQuantity(
37 order.getOrgId(),
38 detail.getMaterialId()
39 );
40
41 // 5. 计算净需求
42 BigDecimal netRequirement = requireQty.subtract(availableQty);
43
44 if (netRequirement.compareTo(BigDecimal.ZERO) > 0) {
45 MaterialRequirement requirement = new MaterialRequirement();
46 requirement.setProductionOrderNo(order.getOrderNo());
47 requirement.setMaterialId(detail.getMaterialId());
48 requirement.setMaterialCode(detail.getMaterialCode());
49 requirement.setMaterialName(detail.getMaterialName());
50 requirement.setRequireQty(requireQty);
51 requirement.setAvailableQty(availableQty);
52 requirement.setNetRequirement(netRequirement);
53 requirement.setRequireDate(order.getPlanStartDate());
54
55 requirements.add(requirement);
56 }
57 }
58 }
59
60 return requirements;
61 }
62}

4. 成本核算

java
1@Service
2public class CostAccountingService {
3
4 /**
5 * 产品成本核算
6 */
7 @Transactional
8 public void calculateProductCost(Long productionOrderId) {
9 ProductionOrder order = productionOrderMapper.selectById(productionOrderId);
10
11 // 1. 计算直接材料成本
12 BigDecimal materialCost = calculateMaterialCost(productionOrderId);
13
14 // 2. 计算直接人工成本
15 BigDecimal laborCost = calculateLaborCost(productionOrderId);
16
17 // 3. 计算制造费用
18 BigDecimal overheadCost = calculateOverheadCost(productionOrderId);
19
20 // 4. 计算总成本
21 BigDecimal totalCost = materialCost.add(laborCost).add(overheadCost);
22
23 // 5. 计算单位成本
24 BigDecimal unitCost = totalCost.divide(
25 order.getQualifiedQuantity(),
26 4,
27 RoundingMode.HALF_UP
28 );
29
30 // 6. 保存成本数据
31 ProductionCost cost = new ProductionCost();
32 cost.setProductionOrderId(productionOrderId);
33 cost.setMaterialCost(materialCost);
34 cost.setLaborCost(laborCost);
35 cost.setOverheadCost(overheadCost);
36 cost.setTotalCost(totalCost);
37 cost.setUnitCost(unitCost);
38 productionCostMapper.insert(cost);
39
40 // 7. 更新产品成本
41 updateProductCost(order.getProductId(), unitCost);
42
43 // 8. 生成成本凭证
44 generateCostVoucher(order, cost);
45 }
46
47 /**
48 * 计算材料成本
49 */
50 private BigDecimal calculateMaterialCost(Long productionOrderId) {
51 // 查询生产领料记录
52 List<MaterialIssue> issues = materialIssueMapper.selectByProductionOrder(
53 productionOrderId
54 );
55
56 BigDecimal totalCost = BigDecimal.ZERO;
57 for (MaterialIssue issue : issues) {
58 // 移动加权平均法计算成本
59 BigDecimal cost = inventoryService.getInventoryCost(
60 issue.getProductId(),
61 issue.getQuantity()
62 );
63 totalCost = totalCost.add(cost);
64 }
65
66 return totalCost;
67 }
68}

5. 财务自动记账

java
1@Service
2public class AutoVoucherService {
3
4 @Autowired
5 private VoucherService voucherService;
6
7 /**
8 * 采购入库自动生成凭证
9 */
10 public void generatePurchaseVoucher(Long purchaseOrderId) {
11 PurchaseOrder order = purchaseOrderMapper.selectById(purchaseOrderId);
12
13 // 借:原材料
14 // 借:应交税费-应交增值税(进项税额)
15 // 贷:应付账款
16
17 VoucherDTO voucher = new VoucherDTO();
18 voucher.setVoucherDate(LocalDate.now());
19 voucher.setVoucherType(VoucherType.ACCOUNTING);
20
21 List<VoucherDetailDTO> details = new ArrayList<>();
22
23 // 借方:原材料
24 VoucherDetailDTO detail1 = new VoucherDetailDTO();
25 detail1.setAccountCode("1403"); // 原材料
26 detail1.setSummary("采购入库-" + order.getOrderNo());
27 detail1.setDebitAmount(order.getTotalAmount());
28 detail1.setCreditAmount(BigDecimal.ZERO);
29 details.add(detail1);
30
31 // 借方:应交增值税
32 VoucherDetailDTO detail2 = new VoucherDetailDTO();
33 detail2.setAccountCode("2221001"); // 应交增值税-进项税额
34 detail2.setSummary("采购入库-" + order.getOrderNo());
35 detail2.setDebitAmount(order.getTaxAmount());
36 detail2.setCreditAmount(BigDecimal.ZERO);
37 details.add(detail2);
38
39 // 贷方:应付账款
40 VoucherDetailDTO detail3 = new VoucherDetailDTO();
41 detail3.setAccountCode("2202"); // 应付账款
42 detail3.setSummary("采购入库-" + order.getOrderNo());
43 detail3.setDebitAmount(BigDecimal.ZERO);
44 detail3.setCreditAmount(order.getFinalAmount());
45 detail3.setAuxiliaryType("supplier");
46 detail3.setAuxiliaryId(order.getSupplierId());
47 details.add(detail3);
48
49 voucher.setDetails(details);
50
51 voucherService.createVoucher(voucher);
52 }
53}

6. 数据权限控制

java
1@Component
2public class DataScopeInterceptor implements Interceptor {
3
4 @Override
5 public Object intercept(Invocation invocation) throws Throwable {
6 // 获取当前用户
7 Long userId = SecurityUtils.getCurrentUserId();
8 User user = userService.getById(userId);
9
10 // 获取数据权限范围
11 DataScope dataScope = user.getDataScope();
12
13 // 根据权限范围添加查询条件
14 if (dataScope == DataScope.ORG) {
15 // 只能查看本组织数据
16 addOrgCondition(invocation, user.getOrgId());
17 } else if (dataScope == DataScope.ORG_AND_CHILDREN) {
18 // 可以查看本组织及子组织数据
19 List<Long> orgIds = getOrgIdsIncludeChildren(user.getOrgId());
20 addOrgInCondition(invocation, orgIds);
21 } else if (dataScope == DataScope.SELF) {
22 // 只能查看自己创建的数据
23 addCreateUserCondition(invocation, userId);
24 }
25 // ALL - 可以查看所有数据,不添加条件
26
27 return invocation.proceed();
28 }
29}

API 接口设计

1. 采购订单接口

java
1@RestController
2@RequestMapping("/api/erp/purchase/order")
3public class PurchaseOrderController {
4
5 @Autowired
6 private PurchaseOrderService purchaseOrderService;
7
8 /**
9 * 创建采购订单
10 */
11 @PostMapping("")
12 public Result<Long> createOrder(@RequestBody @Valid PurchaseOrderDTO dto) {
13 Long orderId = purchaseOrderService.createOrder(dto);
14 return Result.success(orderId);
15 }
16
17 /**
18 * 提交审批
19 */
20 @PostMapping("/{orderId}/submit")
21 public Result<Void> submitForApproval(@PathVariable Long orderId) {
22 purchaseOrderService.submitForApproval(orderId);
23 return Result.success();
24 }
25
26 /**
27 * 采购订单列表
28 */
29 @GetMapping("")
30 public Result<PageResult<PurchaseOrderVO>> listOrders(
31 @RequestParam(required = false) String orderNo,
32 @RequestParam(required = false) Long supplierId,
33 @RequestParam(required = false) Integer status,
34 @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate,
35 @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate,
36 @RequestParam(defaultValue = "1") Integer pageNum,
37 @RequestParam(defaultValue = "20") Integer pageSize) {
38
39 PageResult<PurchaseOrderVO> result = purchaseOrderService.listOrders(
40 orderNo, supplierId, status, startDate, endDate, pageNum, pageSize
41 );
42 return Result.success(result);
43 }
44}

2. 生产订单接口

java
1@RestController
2@RequestMapping("/api/erp/production/order")
3public class ProductionOrderController {
4
5 @Autowired
6 private ProductionOrderService productionOrderService;
7
8 /**
9 * 创建生产订单
10 */
11 @PostMapping("")
12 public Result<Long> createOrder(@RequestBody @Valid ProductionOrderDTO dto) {
13 Long orderId = productionOrderService.createOrder(dto);
14 return Result.success(orderId);
15 }
16
17 /**
18 * 下达生产订单
19 */
20 @PostMapping("/{orderId}/release")
21 public Result<Void> releaseOrder(@PathVariable Long orderId) {
22 productionOrderService.releaseOrder(orderId);
23 return Result.success();
24 }
25
26 /**
27 * 生产报工
28 */
29 @PostMapping("/{orderId}/report")
30 public Result<Void> reportProgress(
31 @PathVariable Long orderId,
32 @RequestBody @Valid ProductionReportDTO dto) {
33
34 productionOrderService.reportProgress(orderId, dto);
35 return Result.success();
36 }
37
38 /**
39 * 完工入库
40 */
41 @PostMapping("/{orderId}/complete")
42 public Result<Void> completeOrder(
43 @PathVariable Long orderId,
44 @RequestBody @Valid ProductionCompleteDTO dto) {
45
46 productionOrderService.completeOrder(orderId, dto);
47 return Result.success();
48 }
49}

3. 财务凭证接口

java
1@RestController
2@RequestMapping("/api/erp/finance/voucher")
3public class VoucherController {
4
5 @Autowired
6 private VoucherService voucherService;
7
8 /**
9 * 创建凭证
10 */
11 @PostMapping("")
12 public Result<Long> createVoucher(@RequestBody @Valid VoucherDTO dto) {
13 Long voucherId = voucherService.createVoucher(dto);
14 return Result.success(voucherId);
15 }
16
17 /**
18 * 审核凭证
19 */
20 @PostMapping("/{voucherId}/check")
21 public Result<Void> checkVoucher(@PathVariable Long voucherId) {
22 voucherService.checkVoucher(voucherId);
23 return Result.success();
24 }
25
26 /**
27 * 记账
28 */
29 @PostMapping("/{voucherId}/post")
30 public Result<Void> postVoucher(@PathVariable Long voucherId) {
31 voucherService.postVoucher(voucherId);
32 return Result.success();
33 }
34
35 /**
36 * 反记账
37 */
38 @PostMapping("/{voucherId}/unpost")
39 public Result<Void> unpostVoucher(@PathVariable Long voucherId) {
40 voucherService.unpostVoucher(voucherId);
41 return Result.success();
42 }
43}

性能优化方案

1. 数据库优化

  • 合理设计索引
  • 使用分区表(按月份分区)
  • 读写分离
  • 定期归档历史数据

2. 缓存优化

  • 缓存基础数据(科目、组织、用户等)
  • 缓存权限数据
  • 使用本地缓存 + Redis 二级缓存

3. 报表优化

  • 使用 ClickHouse 做数据分析
  • 定时同步数据到 ClickHouse
  • 复杂报表异步生成

4. 并发优化

  • 使用乐观锁处理并发
  • 异步处理非核心业务

总结

ERP 系统的核心在于:

  1. 业务集成:打通企业各个业务环节,实现数据共享
  2. 流程规范:通过系统规范业务流程,提高管理效率
  3. 数据一致性:确保各模块数据的一致性和准确性
  4. 权限控制:严格的权限控制体系,保障数据安全
  5. 灵活扩展:支持多组织、多业务场景的扩展

本设计方案基于 Spring Cloud 微服务架构,涵盖财务、采购、销售、库存、生产、人力资源等核心模块,可满足中大型企业的 ERP 需求。

参与讨论