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 (待审批) (待执行) (待验收) (待入库) (待付款) (已完成)关键步骤:
- 创建采购申请(需求部门发起)
- 采购申请审批
- 创建采购订单(采购部门)
- 采购订单审批
- 到货验收(质检部门)
- 采购入库(仓库)
- 采购发票录入(财务)
- 应付款生成
- 付款处理
- 生成会计凭证
2. 订单到收款流程 (O2C)
1销售订单 → 销售发货 → 销售出库 → 销售发票 → 收款2 ↓ ↓ ↓ ↓ ↓3 (待审批) (待发货) (待出库) (待收款) (已完成)关键步骤:
- 创建销售订单
- 销售订单审批
- 信用检查
- 库存预留
- 销售发货
- 销售出库
- 销售发票开具
- 应收款生成
- 收款处理
- 生成会计凭证
3. 生产制造流程
1生产计划 → 物料需求 → 生产订单 → 生产领料 → 生产报工 → 完工入库2 ↓ ↓ ↓ ↓ ↓ ↓3 (计划) (需求分析) (已下达) (生产中) (已报工) (已完工)关键步骤:
- 制定生产计划(根据销售订单或库存补货)
- MRP 运算(物料需求计划)
- 生成生产订单
- 生产订单下达
- 生产领料(从仓库领取物料)
- 生产报工(记录生产进度)
- 质检(成品检验)
- 完工入库
- 成本核算
4. 月末结账流程
1期间检查 → 成本核算 → 损益结转 → 凭证审核 → 记账 → 结账关键步骤:
- 检查期间数据完整性
- 成本核算(材料成本、人工成本、制造费用)
- 自动生成结转凭证(损益结转、成本结转)
- 凭证审核
- 凭证记账
- 月末结账
- 生成财务报表
技术实现方案
1. 工作流引擎(审批流程)
使用 Flowable 实现审批流程:
java
1@Service2public class PurchaseOrderWorkflowService {3 4 @Autowired5 private RuntimeService runtimeService;6 7 @Autowired8 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 variables27 );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@Service2public class SalesOrderService {3 4 @Autowired5 private SalesOrderMapper salesOrderMapper;6 7 @Autowired8 private InventoryServiceClient inventoryServiceClient;9 10 @Autowired11 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@Service2public class MrpService {3 4 @Autowired5 private ProductionOrderMapper productionOrderMapper;6 7 @Autowired8 private BomService bomService;9 10 @Autowired11 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 endDate21 );22 23 List<MaterialRequirement> requirements = new ArrayList<>();24 25 for (ProductionOrder order : orders) {26 // 2. 获取 BOM27 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@Service2public class CostAccountingService {3 4 /**5 * 产品成本核算6 */7 @Transactional8 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_UP28 );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 productionOrderId54 );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@Service2public class AutoVoucherService {3 4 @Autowired5 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@Component2public class DataScopeInterceptor implements Interceptor {3 4 @Override5 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@RestController2@RequestMapping("/api/erp/purchase/order")3public class PurchaseOrderController {4 5 @Autowired6 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, pageSize41 );42 return Result.success(result);43 }44}2. 生产订单接口
java
1@RestController2@RequestMapping("/api/erp/production/order")3public class ProductionOrderController {4 5 @Autowired6 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@RestController2@RequestMapping("/api/erp/finance/voucher")3public class VoucherController {4 5 @Autowired6 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 系统的核心在于:
- 业务集成:打通企业各个业务环节,实现数据共享
- 流程规范:通过系统规范业务流程,提高管理效率
- 数据一致性:确保各模块数据的一致性和准确性
- 权限控制:严格的权限控制体系,保障数据安全
- 灵活扩展:支持多组织、多业务场景的扩展
本设计方案基于 Spring Cloud 微服务架构,涵盖财务、采购、销售、库存、生产、人力资源等核心模块,可满足中大型企业的 ERP 需求。
参与讨论