فهرست منبع

fix:委外计划、预生产计划、采购计划、采购订单

lumaojun 3 هفته پیش
والد
کامیت
76957a65a0
20فایلهای تغییر یافته به همراه905 افزوده شده و 8 حذف شده
  1. 6 1
      easydo-mes/src/main/java/easydo/technology/controller/ProductPrePlanController.java
  2. 56 0
      easydo-mes/src/main/java/easydo/technology/controller/PurchaseOrderController.java
  3. 15 0
      easydo-mes/src/main/java/easydo/technology/controller/PurchasePlanController.java
  4. 35 0
      easydo-mes/src/main/java/easydo/technology/enums/MESEnum.java
  5. 1 0
      easydo-mes/src/main/java/easydo/technology/model/OutsourcingPlan.java
  6. 38 0
      easydo-mes/src/main/java/easydo/technology/model/PurchaseOrder.java
  7. 15 0
      easydo-mes/src/main/java/easydo/technology/model/PurchaseOrderDetail.java
  8. 31 1
      easydo-mes/src/main/java/easydo/technology/model/WarehouseMaterial.java
  9. 21 0
      easydo-mes/src/main/java/easydo/technology/model/WarehouseRecord.java
  10. 16 0
      easydo-mes/src/main/java/easydo/technology/model/vo/OutsourcingPlanVO.java
  11. 17 0
      easydo-mes/src/main/java/easydo/technology/model/vo/ProductPlanVO.java
  12. 21 0
      easydo-mes/src/main/java/easydo/technology/model/vo/ProductPrePlanVO.java
  13. 16 0
      easydo-mes/src/main/java/easydo/technology/model/vo/PurchasePlanVO.java
  14. 11 0
      easydo-mes/src/main/java/easydo/technology/model/vo/WarehouseMaterialVO.java
  15. 114 0
      easydo-mes/src/main/java/easydo/technology/service/FlowNoService.java
  16. 9 0
      easydo-mes/src/main/java/easydo/technology/service/ProductPrePlanService.java
  17. 15 0
      easydo-mes/src/main/java/easydo/technology/service/PurchaseOrderService.java
  18. 207 3
      easydo-mes/src/main/java/easydo/technology/service/impl/ProductPrePlanServiceImpl.java
  19. 214 0
      easydo-mes/src/main/java/easydo/technology/service/impl/PurchaseOrderServiceImpl.java
  20. 47 3
      easydo-mes/src/main/java/easydo/technology/service/impl/PurchasePlanServiceImpl.java

+ 6 - 1
easydo-mes/src/main/java/easydo/technology/controller/ProductPrePlanController.java

@@ -1,5 +1,6 @@
 package easydo.technology.controller;
 
+import easydo.technology.model.vo.ProductPrePlanVO;
 import easydo.technology.service.ProductPrePlanService;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
@@ -22,5 +23,9 @@ public class ProductPrePlanController {
         Map<String, Object> result = productPrePlanService.getPage(map);
         return new ResponseEntity<>(result, HttpStatus.OK);
     }
-}
 
+    @RequestMapping(value = "/save")
+    public Object save(@RequestBody ProductPrePlanVO vo) throws Exception {
+        return new ResponseEntity<>(productPrePlanService.save(vo), HttpStatus.OK);
+    }
+}

+ 56 - 0
easydo-mes/src/main/java/easydo/technology/controller/PurchaseOrderController.java

@@ -0,0 +1,56 @@
+package easydo.technology.controller;
+
+import easydo.technology.model.PurchaseOrder;
+import easydo.technology.service.PurchaseOrderService;
+import easydo.technology.utils.SecurityUtils;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.Map;
+
+@RestController
+@RequestMapping("/purchaseOrder")
+public class PurchaseOrderController {
+
+    @Resource
+    private PurchaseOrderService purchaseOrderService;
+
+    @RequestMapping(value = "/getPage")
+    public Object getPage(@RequestBody Map<String, Object> map) throws Exception {
+        Map<String, Object> result = purchaseOrderService.getPage(map);
+        return new ResponseEntity<>(result, HttpStatus.OK);
+    }
+
+    @RequestMapping(value = "/save")
+    public Object save(@RequestBody PurchaseOrder model) throws Exception {
+        // 校验用户登录状态
+        Long userId = SecurityUtils.getCurrentUserId();
+        if (userId == null) {
+            return new ResponseEntity<>("用户请先登录", HttpStatus.UNAUTHORIZED);
+        }
+        
+        model.setCreateId(userId);
+        return new ResponseEntity<>(purchaseOrderService.save(model), HttpStatus.OK);
+    }
+
+    @RequestMapping(value = "/update")
+    public Object update(@RequestBody PurchaseOrder model) throws Exception {
+        // 校验用户登录状态
+        Long userId = SecurityUtils.getCurrentUserId();
+        if (userId == null) {
+            return new ResponseEntity<>("用户请先登录", HttpStatus.UNAUTHORIZED);
+        }
+        
+        model.setUpdateId(userId);
+        return new ResponseEntity<>(purchaseOrderService.update(model), HttpStatus.OK);
+    }
+
+    @RequestMapping(value = "/remove")
+    public Object remove(@RequestBody PurchaseOrder model) throws Exception {
+        return new ResponseEntity<>(purchaseOrderService.remove(model), HttpStatus.OK);
+    }
+}

+ 15 - 0
easydo-mes/src/main/java/easydo/technology/controller/PurchasePlanController.java

@@ -2,6 +2,7 @@ package easydo.technology.controller;
 
 import easydo.technology.model.PurchasePlan;
 import easydo.technology.service.PurchasePlanService;
+import easydo.technology.utils.SecurityUtils;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -26,11 +27,25 @@ public class PurchasePlanController {
 
     @RequestMapping(value = "/save")
     public Object save(@RequestBody PurchasePlan model) throws Exception {
+        // 校验用户登录状态
+        Long userId = SecurityUtils.getCurrentUserId();
+        if (userId == null) {
+            return new ResponseEntity<>("用户请先登录", HttpStatus.UNAUTHORIZED);
+        }
+        
+        model.setCreateId(userId);
         return new ResponseEntity<>(purchasePlanService.save(model), HttpStatus.OK);
     }
 
     @RequestMapping(value = "/update")
     public Object update(@RequestBody PurchasePlan model) throws Exception {
+        // 校验用户登录状态
+        Long userId = SecurityUtils.getCurrentUserId();
+        if (userId == null) {
+            return new ResponseEntity<>("用户请先登录", HttpStatus.UNAUTHORIZED);
+        }
+        
+        model.setUpdateId(userId);
         return new ResponseEntity<>(purchasePlanService.update(model), HttpStatus.OK);
     }
 

+ 35 - 0
easydo-mes/src/main/java/easydo/technology/enums/MESEnum.java

@@ -17,6 +17,7 @@ public enum MESEnum {
     FLOW_NO_TYPE_SALE_ORDER("sale_order", "销售订单"),
     FLOW_NO_TYPE_WAREHOUSE("warehouse", "仓库管理"),
     FLOW_NO_TYPE_PURCHASE_PLAN("purchase_plan", "采购计划"),
+    FLOW_NO_TYPE_PURCHASE_ORDER("purchase_order", "采购订单"),
     FLOW_NO_TYPE_OUTSOURCING_PLAN("outsourcing_plan", "委外计划"),
 
     PROCESS_STAGE_OF_CATEGORY_PREPARATION("preparation","准备工序"),
@@ -61,6 +62,40 @@ public enum MESEnum {
     SALE_ORDER_OF_STATUS_PARTIALLY("partially", "部分发货"),
     SALE_ORDER_OF_STATUS_SHIPPED("shipped", "已发货"),
     SALE_ORDER_OF_STATUS_COMPLETE("complete", "已完成"),
+
+    FLOW_NO_TYPE_PRODUCT_PLAN("product_plan", "生产计划"),
+
+    PRODUCT_PLAN_OF_STATUS_PENDING("pending", "待进行"),
+    PRODUCT_PLAN_OF_STATUS_PROCESSING("processing", "进行中"),
+    PRODUCT_PLAN_OF_STATUS_COMPLETE("complete", "已完成"),
+    
+    PURCHASE_PLAN_OF_STATUS_PENDING("pending", "待进行"),
+    PURCHASE_PLAN_OF_STATUS_PROCESSING("processing", "进行中"),
+    PURCHASE_PLAN_OF_STATUS_COMPLETE("complete", "已完成"),
+    
+    PURCHASE_ORDER_OF_STATUS_PENDING("pending", "待处理"),
+    PURCHASE_ORDER_OF_STATUS_PROCESSING("processing", "采购中"),
+    PURCHASE_ORDER_OF_STATUS_RECEIVED("received", "已收货"),
+    PURCHASE_ORDER_OF_STATUS_COMPLETE("complete", "已完成"),
+    
+    OUTSOURCING_PLAN_OF_STATUS_PENDING("pending", "待进行"),
+    OUTSOURCING_PLAN_OF_STATUS_PROCESSING("processing", "进行中"),
+    OUTSOURCING_PLAN_OF_STATUS_COMPLETE("complete", "已完成"),
+
+    WAREHOUSE_RECORD_OF_TYPE_LOCK("lock", "锁定"),
+
+    WAREHOUSE_RECORD_OF_REF_TYPE_PRODUCT("product", "生产计划"),
+    WAREHOUSE_RECORD_OF_REF_TYPE_PURCHASE("purchase", "采购计划"),
+    WAREHOUSE_RECORD_OF_REF_TYPE_OUTSOURCING("outsourcing", "委外计划"),
+
+    OUTSOURCING_PLAN_OF_TYPE_PROCESS("process", "工序委外"),
+    OUTSOURCING_PLAN_OF_TYPE_WHOLE("whole", "整单委外"),
+    
+    PURCHASE_ORDER_OF_CATEGORY_REGULAR("regular", "常规采购"),
+    PURCHASE_ORDER_OF_CATEGORY_URGENT("urgent", "特急采购"),
+    PURCHASE_ORDER_OF_CATEGORY_SPORADIC("sporadic", "零星采购"),
+    PURCHASE_ORDER_OF_CATEGORY_BULK("bulk", "大量采购"),
+    PURCHASE_ORDER_OF_CATEGORY_INTERNAL("internal", "集团内部采购"),
     ;
 
     MESEnum(String value, String comment) {

+ 1 - 0
easydo-mes/src/main/java/easydo/technology/model/OutsourcingPlan.java

@@ -22,6 +22,7 @@ public class OutsourcingPlan extends CommonModel {
     private String updateTime;
     private String beginDate;
     private String endDate;
+    private String type;
 
     // 非数据库字段
     private List<OutsourcingPlanDetail> childrenList;

+ 38 - 0
easydo-mes/src/main/java/easydo/technology/model/PurchaseOrder.java

@@ -0,0 +1,38 @@
+package easydo.technology.model;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.List;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class PurchaseOrder extends CommonModel {
+    private String id;
+    private String code;
+    private String name;
+    private String saleOrderId;
+    private String customerId;
+    private Long managerUserId;
+    private String createTime;
+    private String status;
+    private String category;
+    private String planReceiveDate;
+    private String actualReceiveDate;
+    private String purchasePlanId;
+    private Long createId;
+    private Long updateId;
+    private String tenantId;
+    private String updateTime;
+    private String expressNo;
+    private String remark;
+
+    // 非数据库字段,用于级联组装
+    private List<String> emptyField;
+    private List<MinioFile> fileList;
+    private List<PurchaseOrderDetail> childrenList;
+    private SaleOrder saleOrder;
+    private Customer customer;
+    private PurchasePlan purchasePlan;
+    private String managerUserName;  // 负责人姓名(非数据库字段)
+}

+ 15 - 0
easydo-mes/src/main/java/easydo/technology/model/PurchaseOrderDetail.java

@@ -0,0 +1,15 @@
+package easydo.technology.model;
+
+import lombok.Data;
+
+@Data
+public class PurchaseOrderDetail {
+    private String id;
+    private String orderId;
+    private String materialCode;
+    private Double number;
+    private String status;
+
+    // 非数据库字段,用于级联组装
+    private ProductMaterial productMaterial;
+}

+ 31 - 1
easydo-mes/src/main/java/easydo/technology/model/WarehouseMaterial.java

@@ -4,14 +4,44 @@ import easydo.technology.annotation.NotTableField;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 
+import java.math.BigDecimal;
+
 @EqualsAndHashCode(callSuper = true)
 @Data
 public class WarehouseMaterial extends CommonModel {
     private String id;
     private String warehouseId;
     private String materialCode;
-    private Double number;
+
+    /**
+     * 可用库存数量(对应数据库 decimal)
+     */
+    private BigDecimal number;
+
+    /**
+     * 锁定数量(对应数据库 locked_number 字段)
+     */
+    private BigDecimal lockedNumber;
+
+    /**
+     * 冻结数量
+     */
+    private BigDecimal frozenNumber;
+
+    /**
+     * 正常数量
+     */
+    private BigDecimal normalNumber;
+
+    /**
+     * 报废数量
+     */
+    private BigDecimal abandonNumber;
+
     private String createTime;
+    private String updateTime;
+    private Long createId;
+    private Long updateId;
     private String status;
     private String tenantId;
 

+ 21 - 0
easydo-mes/src/main/java/easydo/technology/model/WarehouseRecord.java

@@ -0,0 +1,21 @@
+package easydo.technology.model;
+
+import lombok.Data;
+import java.math.BigDecimal;
+
+@Data
+public class WarehouseRecord {
+    private String id;
+    private String type;
+    private String materialCode;
+    private BigDecimal number;
+    private String createTime;
+    private String fromWarehouseId;
+    private String toWarehouseId;
+    private Long createId;
+    private String remark;
+    private String tenantId;
+    private String refType;
+    private String refId;
+    private String saleOrderId;
+}

+ 16 - 0
easydo-mes/src/main/java/easydo/technology/model/vo/OutsourcingPlanVO.java

@@ -0,0 +1,16 @@
+package easydo.technology.model.vo;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import java.math.BigDecimal;
+import java.util.List;
+
+@Data
+public class OutsourcingPlanVO {
+    private String materialCode;
+    
+    @JsonProperty("allocateNum")
+    private BigDecimal planOutsourcingNumber;
+    
+    private List<WarehouseMaterialVO> warehouseMaterialVoList;
+}

+ 17 - 0
easydo-mes/src/main/java/easydo/technology/model/vo/ProductPlanVO.java

@@ -0,0 +1,17 @@
+package easydo.technology.model.vo;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import java.math.BigDecimal;
+import java.util.List;
+
+@Data
+public class ProductPlanVO {
+    private String materialCode;
+    private String bomId;
+    
+    @JsonProperty("allocateNum")
+    private BigDecimal planProductNumber;
+    
+    private List<WarehouseMaterialVO> warehouseMaterialVoList;
+}

+ 21 - 0
easydo-mes/src/main/java/easydo/technology/model/vo/ProductPrePlanVO.java

@@ -0,0 +1,21 @@
+package easydo.technology.model.vo;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class ProductPrePlanVO {
+    private String saleOrderId;
+
+    private String productPlanName;
+    private String purchasePlanName;
+    private String outsourcingPlanName;
+
+    private String planBeginDate;
+    private String planEndDate;
+
+    private List<ProductPlanVO> productPlanVoList;
+    private List<PurchasePlanVO> purchasePlanVoList;
+    private List<OutsourcingPlanVO> outsourcingPlanVoList;
+}

+ 16 - 0
easydo-mes/src/main/java/easydo/technology/model/vo/PurchasePlanVO.java

@@ -0,0 +1,16 @@
+package easydo.technology.model.vo;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import java.math.BigDecimal;
+import java.util.List;
+
+@Data
+public class PurchasePlanVO {
+    private String materialCode;
+    
+    @JsonProperty("allocateNum")
+    private BigDecimal planPurchaseNumber;
+    
+    private List<WarehouseMaterialVO> warehouseMaterialVoList;
+}

+ 11 - 0
easydo-mes/src/main/java/easydo/technology/model/vo/WarehouseMaterialVO.java

@@ -0,0 +1,11 @@
+package easydo.technology.model.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+public class WarehouseMaterialVO {
+    private String warehouseId;
+    private BigDecimal lockedNumber;
+}

+ 114 - 0
easydo-mes/src/main/java/easydo/technology/service/FlowNoService.java

@@ -36,6 +36,8 @@ public class FlowNoService {
     private final Object salePlanLock = new Object();
     private final Object purchasePlanLock = new Object();
     private final Object outsourcingPlanLock = new Object();
+    private final Object productPlanLock = new Object();
+    private final Object purchaseOrderLock = new Object();
 
 
     /**
@@ -478,6 +480,62 @@ public class FlowNoService {
         }
     }
 
+    /**
+     * 生成生产计划编码 (ProductPlan) - 独立解耦实现
+     */
+    public String generateProductPlanCode(ProductPlan model, Connection connection) throws Exception {
+        synchronized (productPlanLock) {
+            String manualCode = model.getCode();
+            String tenantId = model.getTenantId();
+            if (StringUtil.isNotEmpty(manualCode)) {
+                Map<String, Object> checkMap = new HashMap<>();
+                checkMap.put("code", manualCode);
+                checkMap.put("tenantId", tenantId);
+                int count = (int) jdbcClient.getJdbcCountByMap(checkMap, ProductPlan.class, connection);
+                if (count > 0) {
+                    throw new BizException("生产计划编号已存在: " + manualCode);
+                }
+                return manualCode;
+            }
+
+            while (true) {
+                FlowNo flowNo = new FlowNo();
+                flowNo.setType(MESEnum.FLOW_NO_TYPE_PRODUCT_PLAN.getValue());
+                flowNo.setTenantId(tenantId);
+                flowNo = jdbcClient.getJdbcModel(flowNo, connection);
+                if (flowNo == null) throw new BizException("未配置生产计划流水号规则");
+
+                String currDate = DFY_MD.format(LocalDateTime.now());
+                String currDate2 = DFY_MD_2.format(LocalDateTime.now());
+                if (StringUtil.isEmpty(flowNo.getCurrDate()) || !flowNo.getCurrDate().equals(currDate)) {
+                    flowNo.setCurrDate(currDate);
+                    flowNo.setCurrSeq(1);
+                } else {
+                    flowNo.setCurrSeq(flowNo.getCurrSeq() + 1);
+                }
+
+                String no;
+                if (StringUtil.isEmpty(flowNo.getCurrDate())) {
+                    no = (flowNo.getPrefix() != null ? flowNo.getPrefix() : "") + String.format("%06d", flowNo.getCurrSeq());
+                } else {
+                    no = (flowNo.getPrefix() != null ? flowNo.getPrefix() : "") + currDate2 + String.format("%05d", flowNo.getCurrSeq());
+                }
+                flowNo.setCurrNo(no);
+
+                Map<String, Object> updateMap = new HashMap<>();
+                updateMap.put("type", MESEnum.FLOW_NO_TYPE_PRODUCT_PLAN.getValue());
+                updateMap.put("tenantId", tenantId);
+                jdbcClient.jdbcUpdate(flowNo, updateMap, connection);
+
+                Map<String, Object> checkMap = new HashMap<>();
+                checkMap.put("code", no);
+                checkMap.put("tenantId", tenantId);
+                int count = (int) jdbcClient.getJdbcCountByMap(checkMap, ProductPlan.class, connection);
+                if (count == 0) return no;
+            }
+        }
+    }
+
     /**
      * 生成采购计划编码 (PurchasePlan) - 独立解耦实现
      */
@@ -590,6 +648,62 @@ public class FlowNoService {
         }
     }
 
+    /**
+     * 生成采购订单编码 (PurchaseOrder) - 独立解耦实现
+     */
+    public String generatePurchaseOrderCode(PurchaseOrder model, Connection connection) throws Exception {
+        synchronized (purchaseOrderLock) {
+            String manualCode = model.getCode();
+            String tenantId = model.getTenantId();
+            if (StringUtil.isNotEmpty(manualCode)) {
+                Map<String, Object> checkMap = new HashMap<>();
+                checkMap.put("code", manualCode);
+                checkMap.put("tenantId", tenantId);
+                int count = (int) jdbcClient.getJdbcCountByMap(checkMap, PurchaseOrder.class, connection);
+                if (count > 0) {
+                    throw new BizException("采购订单编号已存在: " + manualCode);
+                }
+                return manualCode;
+            }
+
+            while (true) {
+                FlowNo flowNo = new FlowNo();
+                flowNo.setType(MESEnum.FLOW_NO_TYPE_PURCHASE_ORDER.getValue());
+                flowNo.setTenantId(tenantId);
+                flowNo = jdbcClient.getJdbcModel(flowNo, connection);
+                if (flowNo == null) throw new BizException("未配置采购订单流水号规则");
+
+                String currDate = DFY_MD.format(LocalDateTime.now());
+                String currDate2 = DFY_MD_2.format(LocalDateTime.now());
+                if (StringUtil.isEmpty(flowNo.getCurrDate()) || !flowNo.getCurrDate().equals(currDate)) {
+                    flowNo.setCurrDate(currDate);
+                    flowNo.setCurrSeq(1);
+                } else {
+                    flowNo.setCurrSeq(flowNo.getCurrSeq() + 1);
+                }
+
+                String no;
+                if (StringUtil.isEmpty(flowNo.getCurrDate())) {
+                    no = (flowNo.getPrefix() != null ? flowNo.getPrefix() : "") + String.format("%06d", flowNo.getCurrSeq());
+                } else {
+                    no = (flowNo.getPrefix() != null ? flowNo.getPrefix() : "") + currDate2 + String.format("%05d", flowNo.getCurrSeq());
+                }
+                flowNo.setCurrNo(no);
+
+                Map<String, Object> updateMap = new HashMap<>();
+                updateMap.put("type", MESEnum.FLOW_NO_TYPE_PURCHASE_ORDER.getValue());
+                updateMap.put("tenantId", tenantId);
+                jdbcClient.jdbcUpdate(flowNo, updateMap, connection);
+
+                Map<String, Object> checkMap = new HashMap<>();
+                checkMap.put("code", no);
+                checkMap.put("tenantId", tenantId);
+                int count = (int) jdbcClient.getJdbcCountByMap(checkMap, PurchaseOrder.class, connection);
+                if (count == 0) return no;
+            }
+        }
+    }
+
     /**
      * 原始流水号生成方法
      */

+ 9 - 0
easydo-mes/src/main/java/easydo/technology/service/ProductPrePlanService.java

@@ -1,8 +1,17 @@
 package easydo.technology.service;
 
+import easydo.technology.model.vo.ProductPrePlanVO;
+
 import java.util.Map;
 
 public interface ProductPrePlanService {
     Map<String, Object> getPage(Map<String, Object> map) throws Exception;
+
+    /**
+     * 保存预生产计划
+     * 同步自 Go 版 productPrePlanSave 逻辑
+     * 处理销售订单状态更新、生成生产/采购/委外计划及库存锁定
+     */
+    ProductPrePlanVO save(ProductPrePlanVO vo) throws Exception;
 }
 

+ 15 - 0
easydo-mes/src/main/java/easydo/technology/service/PurchaseOrderService.java

@@ -0,0 +1,15 @@
+package easydo.technology.service;
+
+import easydo.technology.model.PurchaseOrder;
+
+import java.util.Map;
+
+public interface PurchaseOrderService {
+    Map<String, Object> getPage(Map<String, Object> map) throws Exception;
+
+    PurchaseOrder save(PurchaseOrder model) throws Exception;
+
+    PurchaseOrder update(PurchaseOrder model) throws Exception;
+
+    PurchaseOrder remove(PurchaseOrder model) throws Exception;
+}

+ 207 - 3
easydo-mes/src/main/java/easydo/technology/service/impl/ProductPrePlanServiceImpl.java

@@ -4,8 +4,11 @@ import easydo.technology.components.JdbcClient;
 import easydo.technology.enums.MESEnum;
 import easydo.technology.exception.BizException;
 import easydo.technology.model.*;
+import easydo.technology.model.vo.*;
+import easydo.technology.service.FlowNoService;
 import easydo.technology.service.ProductPrePlanService;
 import easydo.technology.system.model.SysUser;
+import easydo.technology.utils.SecurityUtils;
 import easydo.technology.utils.StringUtil;
 import org.springframework.stereotype.Service;
 
@@ -14,6 +17,7 @@ import javax.sql.DataSource;
 import java.sql.Connection;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 @Service
 public class ProductPrePlanServiceImpl implements ProductPrePlanService {
@@ -22,6 +26,8 @@ public class ProductPrePlanServiceImpl implements ProductPrePlanService {
     private JdbcClient jdbcClient;
     @Resource
     private DataSource dataSource;
+    @Resource
+    private FlowNoService flowNoService;
 
     @Override
     @SuppressWarnings("unchecked")
@@ -144,13 +150,211 @@ public class ProductPrePlanServiceImpl implements ProductPrePlanService {
                     }
                 }
             }
-
             return result;
         } catch (Exception e) {
             throw new BizException(e.getMessage());
         } finally {
-            connection.close();
+            if (connection != null) connection.close();
         }
     }
-}
 
+    @Override
+    public ProductPrePlanVO save(ProductPrePlanVO vo) throws Exception {
+        Connection connection = dataSource.getConnection();
+        connection.setAutoCommit(false);
+        try {
+            // 获取当前登录用户 ID,与 Go 版本从 session 取 user_id 逻辑对齐
+            Long userId = SecurityUtils.getCurrentUserId();
+
+            // 1. 更新销售订单状态为“备货中” (processing)
+            SaleOrder saleOrder = new SaleOrder();
+            saleOrder.setId(vo.getSaleOrderId());
+            saleOrder = jdbcClient.getJdbcModelById(saleOrder, connection);
+            if (saleOrder == null) throw new BizException("销售订单不存在");
+            
+            saleOrder.setStatus(MESEnum.SALE_ORDER_OF_STATUS_PROCESSING.getValue());
+            jdbcClient.jdbcUpdateById(saleOrder, connection);
+
+            // 2. 处理生产计划 (ProductPlan)
+            if (vo.getProductPlanVoList() != null && !vo.getProductPlanVoList().isEmpty()) {
+                List<ProductPlanVO> planFilterList = vo.getProductPlanVoList().stream()
+                        .filter(item -> item.getPlanProductNumber() != null && item.getPlanProductNumber().doubleValue() > 0)
+                        .collect(Collectors.toList());
+                
+                if (!planFilterList.isEmpty()) {
+                    ProductPlan productPlan = new ProductPlan();
+                    productPlan.setTenantId(saleOrder.getTenantId());
+                    productPlan.setSaleOrderId(saleOrder.getId());
+                    
+                    // 生成生产计划流水号
+                    String code = flowNoService.generateProductPlanCode(productPlan, connection);
+                    productPlan.setCode(code);
+                    productPlan.setName(StringUtil.isNotEmpty(vo.getProductPlanName()) ? vo.getProductPlanName() : code);
+                    productPlan.setStatus(MESEnum.PRODUCT_PLAN_OF_STATUS_PENDING.getValue());
+                    productPlan.setBeginDate(vo.getPlanBeginDate());
+                    productPlan.setEndDate(vo.getPlanEndDate());
+                    productPlan.setCreateId(userId);
+                    
+                    jdbcClient.jdbcInsert(productPlan, connection);
+
+                    // 插入生产计划 BOM 明细 (ProductPlanBom)
+                    for (ProductPlanVO detailVo : planFilterList) {
+                        ProductPlanBom planBom = new ProductPlanBom();
+                        planBom.setPlanId(productPlan.getId());
+                        planBom.setBomId(detailVo.getBomId());
+                        // 修复类型不匹配:BigDecimal 转 Double
+                        planBom.setNumber(detailVo.getPlanProductNumber() == null ? null : detailVo.getPlanProductNumber().doubleValue());
+
+                        // 查找 BOM 关联的工艺路线和质检方案
+                        ProductBom bom = new ProductBom();
+                        bom.setId(detailVo.getBomId());
+                        bom = jdbcClient.getJdbcModelById(bom, connection);
+                        if (bom != null) {
+                            planBom.setRouteId(bom.getRouteId());
+                            ProcessRoute route = new ProcessRoute();
+                            route.setId(bom.getRouteId());
+                            route = jdbcClient.getJdbcModelById(route, connection);
+                            if (route != null) {
+                                planBom.setInspectProgramId(route.getInspectProgramId());
+                            }
+                        }
+                        jdbcClient.jdbcInsert(planBom, connection);
+                    }
+
+                    // 处理库存锁定 (WarehouseRecord + WarehouseMaterial)
+                    for (ProductPlanVO detailVo : vo.getProductPlanVoList()) {
+                        if (detailVo.getWarehouseMaterialVoList() != null) {
+                            lockWarehouse(detailVo.getWarehouseMaterialVoList(), detailVo.getMaterialCode(), 
+                                    MESEnum.WAREHOUSE_RECORD_OF_REF_TYPE_PRODUCT.getValue(), productPlan.getId(), 
+                                    saleOrder, userId, connection);
+                        }
+                    }
+                }
+            }
+
+            // 3. 处理采购计划 (PurchasePlan)
+            if (vo.getPurchasePlanVoList() != null && !vo.getPurchasePlanVoList().isEmpty()) {
+                List<PurchasePlanVO> planFilterList = vo.getPurchasePlanVoList().stream()
+                        .filter(item -> item.getPlanPurchaseNumber() != null && item.getPlanPurchaseNumber().doubleValue() > 0)
+                        .collect(Collectors.toList());
+
+                if (!planFilterList.isEmpty()) {
+                    PurchasePlan purchasePlan = new PurchasePlan();
+                    purchasePlan.setTenantId(saleOrder.getTenantId());
+                    purchasePlan.setSaleOrderId(saleOrder.getId());
+                    
+                    String code = flowNoService.generatePurchasePlanCode(purchasePlan, connection);
+                    purchasePlan.setCode(code);
+                    purchasePlan.setName(StringUtil.isNotEmpty(vo.getPurchasePlanName()) ? vo.getPurchasePlanName() : code);
+                    purchasePlan.setStatus(MESEnum.PURCHASE_PLAN_OF_STATUS_PENDING.getValue());
+                    purchasePlan.setBeginDate(vo.getPlanBeginDate());
+                    purchasePlan.setEndDate(vo.getPlanEndDate());
+                    purchasePlan.setCreateId(userId);
+                    
+                    jdbcClient.jdbcInsert(purchasePlan, connection);
+
+                    for (PurchasePlanVO detailVo : planFilterList) {
+                        PurchasePlanDetail detail = new PurchasePlanDetail();
+                        detail.setPlanId(purchasePlan.getId());
+                        detail.setMaterialCode(detailVo.getMaterialCode());
+                        detail.setNumber(detailVo.getPlanPurchaseNumber());
+                        jdbcClient.jdbcInsert(detail, connection);
+                    }
+
+                    for (PurchasePlanVO detailVo : vo.getPurchasePlanVoList()) {
+                        if (detailVo.getWarehouseMaterialVoList() != null) {
+                            lockWarehouse(detailVo.getWarehouseMaterialVoList(), detailVo.getMaterialCode(), 
+                                    MESEnum.WAREHOUSE_RECORD_OF_REF_TYPE_PURCHASE.getValue(), purchasePlan.getId(), 
+                                    saleOrder, userId, connection);
+                        }
+                    }
+                }
+            }
+
+            // 4. 处理委外计划 (OutsourcingPlan)
+            if (vo.getOutsourcingPlanVoList() != null && !vo.getOutsourcingPlanVoList().isEmpty()) {
+                List<OutsourcingPlanVO> planFilterList = vo.getOutsourcingPlanVoList().stream()
+                        .filter(item -> item.getPlanOutsourcingNumber() != null && item.getPlanOutsourcingNumber().doubleValue() > 0)
+                        .collect(Collectors.toList());
+
+                if (!planFilterList.isEmpty()) {
+                    OutsourcingPlan outsourcingPlan = new OutsourcingPlan();
+                    outsourcingPlan.setTenantId(saleOrder.getTenantId());
+                    outsourcingPlan.setSaleOrderId(saleOrder.getId());
+                    
+                    String code = flowNoService.generateOutsourcingPlanCode(outsourcingPlan, connection);
+                    outsourcingPlan.setCode(code);
+                    outsourcingPlan.setName(StringUtil.isNotEmpty(vo.getOutsourcingPlanName()) ? vo.getOutsourcingPlanName() : code);
+                    outsourcingPlan.setStatus(MESEnum.OUTSOURCING_PLAN_OF_STATUS_PENDING.getValue());
+                    outsourcingPlan.setBeginDate(vo.getPlanBeginDate());
+                    outsourcingPlan.setEndDate(vo.getPlanEndDate());
+                    outsourcingPlan.setCreateId(userId);
+                    
+                    jdbcClient.jdbcInsert(outsourcingPlan, connection);
+
+                    for (OutsourcingPlanVO detailVo : planFilterList) {
+                        OutsourcingPlanDetail detail = new OutsourcingPlanDetail();
+                        detail.setPlanId(outsourcingPlan.getId());
+                        detail.setMaterialCode(detailVo.getMaterialCode());
+                        detail.setNumber(detailVo.getPlanOutsourcingNumber());
+                        jdbcClient.jdbcInsert(detail, connection);
+                    }
+
+                    for (OutsourcingPlanVO detailVo : vo.getOutsourcingPlanVoList()) {
+                        if (detailVo.getWarehouseMaterialVoList() != null) {
+                            lockWarehouse(detailVo.getWarehouseMaterialVoList(), detailVo.getMaterialCode(), 
+                                    MESEnum.WAREHOUSE_RECORD_OF_REF_TYPE_OUTSOURCING.getValue(), outsourcingPlan.getId(), 
+                                    saleOrder, userId, connection);
+                        }
+                    }
+                }
+            }
+
+            connection.commit();
+            return vo;
+        } catch (Exception e) {
+            connection.rollback();
+            throw new BizException(e.getMessage());
+        } finally {
+            if (connection != null) connection.close();
+        }
+    }
+
+    /**
+     * 内部方法:执行库存锁定逻辑 (WarehouseRecord + 更新 WarehouseMaterial)
+     */
+    private void lockWarehouse(List<WarehouseMaterialVO> wmVoList, String materialCode, String refType, String refId, SaleOrder saleOrder, Long userId, Connection connection) throws Exception {
+        for (WarehouseMaterialVO wmVo : wmVoList) {
+            if (wmVo.getLockedNumber() == null || wmVo.getLockedNumber().doubleValue() <= 0) continue;
+
+            // 1. 插入锁定记录
+            WarehouseRecord record = new WarehouseRecord();
+            record.setType(MESEnum.WAREHOUSE_RECORD_OF_TYPE_LOCK.getValue());
+            record.setMaterialCode(materialCode);
+            record.setNumber(wmVo.getLockedNumber());
+            record.setFromWarehouseId(wmVo.getWarehouseId());
+            record.setTenantId(saleOrder.getTenantId());
+            record.setRefType(refType);
+            record.setRefId(refId);
+            record.setSaleOrderId(saleOrder.getId());
+            record.setCreateId(userId);
+            jdbcClient.jdbcInsert(record, connection);
+
+            // 2. 更新库存表可用数量与锁定数量
+            WarehouseMaterial wm = new WarehouseMaterial();
+            wm.setWarehouseId(wmVo.getWarehouseId());
+            wm.setMaterialCode(materialCode);
+            wm = jdbcClient.getJdbcModel(wm, connection);
+            if (wm != null) {
+                // 可用库存 number 扣减,锁定库存 lockedNumber 增加
+                wm.setNumber(wm.getNumber() == null ? null : wm.getNumber().subtract(wmVo.getLockedNumber()));
+                wm.setLockedNumber((wm.getLockedNumber() != null ? wm.getLockedNumber() : java.math.BigDecimal.ZERO)
+                        .add(wmVo.getLockedNumber()));
+                wm.setUpdateId(userId);
+
+                // 根据主键更新(WarehouseMaterial 模型包含 id 字段)
+                jdbcClient.jdbcUpdateById(wm, connection);
+            }
+        }
+    }
+}

+ 214 - 0
easydo-mes/src/main/java/easydo/technology/service/impl/PurchaseOrderServiceImpl.java

@@ -0,0 +1,214 @@
+package easydo.technology.service.impl;
+
+import easydo.technology.components.JdbcClient;
+import easydo.technology.enums.MESEnum;
+import easydo.technology.exception.BizException;
+import easydo.technology.model.*;
+import easydo.technology.service.FlowNoService;
+import easydo.technology.service.PurchaseOrderService;
+import easydo.technology.system.model.SysUser;
+import easydo.technology.utils.StringUtil;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+@Service
+public class PurchaseOrderServiceImpl implements PurchaseOrderService {
+
+    @Resource
+    private JdbcClient jdbcClient;
+
+    @Resource
+    private DataSource dataSource;
+
+    @Resource
+    private FlowNoService flowNoService;
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Map<String, Object> getPage(Map<String, Object> map) throws Exception {
+        Connection connection = dataSource.getConnection();
+        try {
+            // 1. 获取主表分页数据
+            Map<String, Object> result = jdbcClient.getJdbcPage(map, PurchaseOrder.class, connection);
+            List<PurchaseOrder> list = (List<PurchaseOrder>) result.get("records");
+            if (list == null || list.isEmpty()) {
+                if (result != null) {
+                    result.put("records", new ArrayList<>());
+                }
+                return result;
+            }
+
+            for (PurchaseOrder model : list) {
+                // 2. 补全文件列表 FileList
+                try {
+                    jdbcClient.getMinioFile(model, connection);
+                } catch (Exception e) {
+                    // 打印错误但继续执行
+                }
+
+                // 3. 补全采购计划 PurchasePlan
+                if (model.getPurchasePlanId() != null) {
+                    PurchasePlan purchasePlanParam = new PurchasePlan();
+                    purchasePlanParam.setId(model.getPurchasePlanId());
+                    model.setPurchasePlan(jdbcClient.getJdbcModelById(purchasePlanParam, connection));
+                }
+
+                // 4. 补全销售订单 SaleOrder
+                if (model.getSaleOrderId() != null) {
+                    SaleOrder saleOrderParam = new SaleOrder();
+                    saleOrderParam.setId(model.getSaleOrderId());
+                    model.setSaleOrder(jdbcClient.getJdbcModelById(saleOrderParam, connection));
+                }
+
+                // 5. 补全客户信息 Customer
+                if (model.getCustomerId() != null) {
+                    Customer customerParam = new Customer();
+                    customerParam.setId(model.getCustomerId());
+                    model.setCustomer(jdbcClient.getJdbcModelById(customerParam, connection));
+                }
+
+                // 6. 补全负责人姓名 ManagerUserName
+                if (model.getManagerUserId() != null) {
+                    SysUser managerParam = new SysUser();
+                    managerParam.setId(model.getManagerUserId());
+                    SysUser manager = jdbcClient.getJdbcModelById(managerParam, connection);
+                    if (manager != null) {
+                        model.setManagerUserName(manager.getNickName());
+                    }
+                }
+
+                // 7. 补全明细列表 ChildrenList
+                PurchaseOrderDetail detailParam = new PurchaseOrderDetail();
+                detailParam.setOrderId(model.getId());
+                List<PurchaseOrderDetail> detailList = jdbcClient.getJdbcList(detailParam, connection);
+                if (detailList != null) {
+                    for (PurchaseOrderDetail detail : detailList) {
+                        // 6.1 补全明细中的物料信息 ProductMaterial
+                        if (detail.getMaterialCode() != null) {
+                            ProductMaterial materialParam = new ProductMaterial();
+                            materialParam.setCode(detail.getMaterialCode());
+                            detail.setProductMaterial(jdbcClient.getJdbcModel(materialParam, connection));
+                        }
+                    }
+                    model.setChildrenList(detailList);
+                } else {
+                    model.setChildrenList(new ArrayList<>());
+                }
+            }
+
+            result.put("records", list);
+            return result;
+        } catch (Exception e) {
+            throw new BizException(e.getMessage());
+        } finally {
+            if (connection != null) {
+                connection.close();
+            }
+        }
+    }
+
+    @Override
+    public PurchaseOrder save(PurchaseOrder model) throws Exception {
+        Connection connection = dataSource.getConnection();
+        connection.setAutoCommit(false);
+        try {
+            // 1) 生成编码(支持手填校验 + 自动生成)
+            String code = flowNoService.generatePurchaseOrderCode(model, connection);
+            model.setCode(code);
+
+            // 2) 初始状态 pending
+            model.setStatus(MESEnum.PURCHASE_ORDER_OF_STATUS_PENDING.getValue());
+
+            // 3) 插入主表(会自动保存附件 fileList)
+            jdbcClient.jdbcInsert(model, connection);
+
+            // 4) 插入明细
+            List<PurchaseOrderDetail> detailList = model.getChildrenList();
+            if (detailList != null) {
+                for (PurchaseOrderDetail detail : detailList) {
+                    detail.setOrderId(model.getId());
+                    jdbcClient.jdbcInsert(detail, connection);
+                }
+            }
+
+            // 5) 更新采购计划状态为 processing
+            if (StringUtil.isNotEmpty(model.getPurchasePlanId())) {
+                PurchasePlan purchasePlan = new PurchasePlan();
+                purchasePlan.setId(model.getPurchasePlanId());
+                purchasePlan.setStatus(MESEnum.PURCHASE_PLAN_OF_STATUS_PROCESSING.getValue());
+                jdbcClient.jdbcUpdateById(purchasePlan, connection);
+            }
+
+            connection.commit();
+            return model;
+        } catch (Exception e) {
+            connection.rollback();
+            throw new BizException(e.getMessage());
+        } finally {
+            connection.close();
+        }
+    }
+
+    @Override
+    public PurchaseOrder update(PurchaseOrder model) throws Exception {
+        Connection connection = dataSource.getConnection();
+        connection.setAutoCommit(false);
+        try {
+            // 1) 更新主表(会自动保存附件 fileList)
+            jdbcClient.jdbcUpdateById(model, connection);
+
+            // 2) 删除旧明细
+            PurchaseOrderDetail removeParam = new PurchaseOrderDetail();
+            removeParam.setOrderId(model.getId());
+            jdbcClient.jdbcRemove(removeParam, connection);
+
+            // 3) 插入新明细
+            List<PurchaseOrderDetail> detailList = model.getChildrenList();
+            if (detailList != null) {
+                for (PurchaseOrderDetail detail : detailList) {
+                    detail.setOrderId(model.getId());
+                    jdbcClient.jdbcInsert(detail, connection);
+                }
+            }
+
+            connection.commit();
+            return model;
+        } catch (Exception e) {
+            connection.rollback();
+            throw new BizException(e.getMessage());
+        } finally {
+            connection.close();
+        }
+    }
+
+    @Override
+    public PurchaseOrder remove(PurchaseOrder model) throws Exception {
+        Connection connection = dataSource.getConnection();
+        connection.setAutoCommit(false);
+        try {
+            // 1) 删除主表(JdbcClient 会自动删除附件)
+            jdbcClient.jdbcRemoveById(model, connection);
+
+            // 2) 删除明细
+            PurchaseOrderDetail removeParam = new PurchaseOrderDetail();
+            removeParam.setOrderId(model.getId());
+            jdbcClient.jdbcRemove(removeParam, connection);
+
+            connection.commit();
+            return model;
+        } catch (Exception e) {
+            connection.rollback();
+            throw new BizException(e.getMessage());
+        } finally {
+            connection.close();
+        }
+    }
+
+
+}

+ 47 - 3
easydo-mes/src/main/java/easydo/technology/service/impl/PurchasePlanServiceImpl.java

@@ -2,13 +2,16 @@ package easydo.technology.service.impl;
 
 import easydo.technology.components.JdbcClient;
 import easydo.technology.exception.BizException;
+import easydo.technology.model.Customer;
 import easydo.technology.model.ProductMaterial;
 import easydo.technology.model.PurchasePlan;
 import easydo.technology.model.PurchasePlanDetail;
 import easydo.technology.model.SaleOrder;
+import easydo.technology.model.SaleOrderDetail;
 import easydo.technology.service.FlowNoService;
 import easydo.technology.service.PurchasePlanService;
 import easydo.technology.system.model.SysUser;
+import easydo.technology.utils.StringUtil;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
@@ -53,11 +56,52 @@ public class PurchasePlanServiceImpl implements PurchasePlanService {
                     // 打印错误但继续执行,参考 Go 版 utils.PrintSearchFileErr
                 }
 
-                // 3. 补全销售订单 SaleOrder
+                // 3. 补全销售订单 SaleOrder 及其明细
                 if (model.getSaleOrderId() != null) {
                     SaleOrder saleOrderParam = new SaleOrder();
                     saleOrderParam.setId(model.getSaleOrderId());
-                    model.setSaleOrder(jdbcClient.getJdbcModelById(saleOrderParam, connection));
+                    SaleOrder saleOrder = jdbcClient.getJdbcModelById(saleOrderParam, connection);
+                    
+                    if (saleOrder != null) {
+                        // 3.1 获取销售订单明细列表
+                        SaleOrderDetail saleOrderDetailParam = new SaleOrderDetail();
+                        saleOrderDetailParam.setOrderId(saleOrder.getId());
+                        List<SaleOrderDetail> saleOrderDetailList = jdbcClient.getJdbcList(saleOrderDetailParam, connection);
+                        
+                        if (saleOrderDetailList != null) {
+                            for (SaleOrderDetail detail : saleOrderDetailList) {
+                                // 3.2 补全销售订单明细中的物料信息
+                                if (detail.getMaterialCode() != null) {
+                                    ProductMaterial materialParam = new ProductMaterial();
+                                    materialParam.setCode(detail.getMaterialCode());
+                                    detail.setMaterial(jdbcClient.getJdbcModel(materialParam, connection));
+                                }
+                            }
+                            saleOrder.setChildrenList(saleOrderDetailList);
+                        }
+                        
+                        // 3.3 补全销售订单的负责人姓名 ManagerName
+                        if (StringUtil.isNotEmpty(saleOrder.getManagerId())) {
+                            SysUser managerParam = new SysUser();
+                            managerParam.setId(saleOrder.getManagerId());
+                            SysUser manager = jdbcClient.getJdbcModelById(managerParam, connection);
+                            if (manager != null) {
+                                saleOrder.setManagerName(manager.getNickName());
+                            }
+                        }
+                        
+                        // 3.4 补全销售订单的客户名称 CustomerName
+                        if (StringUtil.isNotEmpty(saleOrder.getCustomerId())) {
+                            Customer customerParam = new Customer();
+                            customerParam.setId(saleOrder.getCustomerId());
+                            Customer customer = jdbcClient.getJdbcModelById(customerParam, connection);
+                            if (customer != null) {
+                                saleOrder.setCustomerName(customer.getName());
+                            }
+                        }
+                        
+                        model.setSaleOrder(saleOrder);
+                    }
                 }
 
                 // 4. 补全采购员姓名 PurchaseUserName (从 SysUser 获取 NickName)
@@ -110,7 +154,7 @@ public class PurchasePlanServiceImpl implements PurchasePlanService {
             String code = flowNoService.generatePurchasePlanCode(model, connection);
             model.setCode(code);
 
-            // 2) 初始状态 pending(与 Go 端一致)
+            // 2) 初始状态 pending
             model.setStatus("pending");
 
             // 3) 插入主表(会自动保存附件 fileList)